?? buffer.c
字號:
struct buffer_head * getblk(int dev,int block){ struct buffer_head * tmp, * bh;repeat:
// 搜索hash 表,如果指定塊已經(jīng)在高速緩沖中,則返回對應(yīng)緩沖區(qū)頭指針,退出。 if (bh = get_hash_table(dev,block)) return bh;
// 掃描空閑數(shù)據(jù)塊鏈表,尋找空閑緩沖區(qū)。
// 首先讓tmp 指向空閑鏈表的第一個空閑緩沖區(qū)頭。 tmp = free_list; do {
// 如果該緩沖區(qū)正被使用(引用計數(shù)不等于0),則繼續(xù)掃描下一項。
if (tmp->b_count)
continue;
// 如果緩沖頭指針bh 為空,或者tmp 所指緩沖頭的標(biāo)志(修改、鎖定)權(quán)重小于bh 頭標(biāo)志的權(quán)重,
// 則讓bh 指向該tmp 緩沖區(qū)頭。如果該tmp 緩沖區(qū)頭表明緩沖區(qū)既沒有修改也沒有鎖定標(biāo)志置位,
// 則說明已為指定設(shè)備上的塊取得對應(yīng)的高速緩沖區(qū),則退出循環(huán)。 if (!bh || BADNESS(tmp)<BADNESS(bh)) { bh = tmp; if (!BADNESS(tmp)) break; }/* 重復(fù)操作直到找到適合的緩沖區(qū) */ } while ((tmp = tmp->b_next_free) != free_list);
// 如果所有緩沖區(qū)都正被使用(所有緩沖區(qū)的頭部引用計數(shù)都>0),
// 則睡眠,等待有空閑的緩沖區(qū)可用。 if (!bh) { sleep_on(&buffer_wait); goto repeat; }
// 等待該緩沖區(qū)解鎖(如果已被上鎖的話)。 wait_on_buffer(bh);
// 如果該緩沖區(qū)又被其它任務(wù)使用的話,只好重復(fù)上述過程。 if (bh->b_count) goto repeat;
// 如果該緩沖區(qū)已被修改,則將數(shù)據(jù)寫盤,并再次等待緩沖區(qū)解鎖。如果該緩沖區(qū)又被其它任務(wù)使用
// 的話,只好再重復(fù)上述過程。 while (bh->b_dirt) { sync_dev(bh->b_dev); wait_on_buffer(bh); if (bh->b_count) goto repeat; }/* 注意!!當(dāng)進(jìn)程為了等待該緩沖塊而睡眠時,其它進(jìn)程可能已經(jīng)將該緩沖塊 *//* 加入進(jìn)高速緩沖中,所以要對此進(jìn)行檢查。 */
// 在高速緩沖hash 表中檢查指定設(shè)備和塊的緩沖區(qū)是否已經(jīng)被加入進(jìn)去。如果是的話,就再次重復(fù)
// 上述過程。 if (find_buffer(dev,block)) goto repeat;/* OK,最終我們知道該緩沖區(qū)是指定參數(shù)的唯一一塊, *//* 而且還沒有被使用(b_count=0),未被上鎖(b_lock=0),并且是干凈的(未被修改的) */
// 于是讓我們占用此緩沖區(qū)。置引用計數(shù)為1,復(fù)位修改標(biāo)志和有效(更新)標(biāo)志。 bh->b_count=1; bh->b_dirt=0; bh->b_uptodate=0;
// 從hash 隊列和空閑塊鏈表中移出該緩沖區(qū)頭,讓該緩沖區(qū)用于指定設(shè)備和其上的指定塊。 remove_from_queues(bh); bh->b_dev=dev; bh->b_blocknr=block;
// 然后根據(jù)此新的設(shè)備號和塊號重新插入空閑鏈表和hash 隊列新位置處。并最終返回緩沖頭指針。 insert_into_queues(bh); return bh;}
//// 釋放指定的緩沖區(qū)。
// 等待該緩沖區(qū)解鎖。引用計數(shù)遞減1。喚醒等待空閑緩沖區(qū)的進(jìn)程。void brelse(struct buffer_head * buf){ if (!buf) // 如果緩沖頭指針無效則返回。 return; wait_on_buffer(buf); if (!(buf->b_count--)) panic("Trying to free free buffer"); wake_up(&buffer_wait);}/* * 從設(shè)備上讀取指定的數(shù)據(jù)塊并返回含有數(shù)據(jù)的緩沖區(qū)。如果指定的塊不存在 * 則返回NULL。 */
//// 從指定設(shè)備上讀取指定的數(shù)據(jù)塊。struct buffer_head * bread(int dev,int block){ struct buffer_head * bh;
// 在高速緩沖中申請一塊緩沖區(qū)。如果返回值是NULL 指針,表示內(nèi)核出錯,死機(jī)。 if (!(bh=getblk(dev,block))) panic("bread: getblk returned NULL\n");
// 如果該緩沖區(qū)中的數(shù)據(jù)是有效的(已更新的)可以直接使用,則返回。 if (bh->b_uptodate) return bh;
// 否則調(diào)用ll_rw_block()函數(shù),產(chǎn)生讀設(shè)備塊請求。并等待緩沖區(qū)解鎖。 ll_rw_block(READ,bh); wait_on_buffer(bh);
// 如果該緩沖區(qū)已更新,則返回緩沖區(qū)頭指針,退出。 if (bh->b_uptodate) return bh;
// 否則表明讀設(shè)備操作失敗,釋放該緩沖區(qū),返回NULL 指針,退出。 brelse(bh); return NULL;}
//// 復(fù)制內(nèi)存塊。
// 從from 地址復(fù)制一塊數(shù)據(jù)到to 位置。
extern __inline void COPYBLK(char* from, char* to)
{_asm{ pushf
mov ecx,BLOCK_SIZE/4
mov esi,from
mov edi,to
cld
rep movsd popf
}}/*#define COPYBLK(from,to) \__asm__("cld\n\t" \ "rep\n\t" \ "movsl\n\t" \ ::"c" (BLOCK_SIZE/4),"S" (from),"D" (to) \ :"cx","di","si")*//* * bread_page 一次讀四個緩沖塊內(nèi)容讀到內(nèi)存指定的地址。它是一個完整的函數(shù),
* 因?yàn)橥瑫r讀取四塊可以獲得速度上的好處,不用等著讀一塊,再讀一塊了。 */
//// 讀設(shè)備上一個頁面(4 個緩沖塊)的內(nèi)容到內(nèi)存指定的地址。void bread_page(unsigned long address,int dev,int b[4]){ struct buffer_head * bh[4]; int i;
// 循環(huán)執(zhí)行4 次,讀一頁內(nèi)容。 for (i=0 ; i<4 ; i++) if (b[i]) {
// 取高速緩沖中指定設(shè)備和塊號的緩沖區(qū),如果該緩沖區(qū)數(shù)據(jù)無效則產(chǎn)生讀設(shè)備請求。 if (bh[i] = getblk(dev,b[i])) if (!bh[i]->b_uptodate) ll_rw_block(READ,bh[i]); } else bh[i] = NULL;
// 將4 塊緩沖區(qū)上的內(nèi)容順序復(fù)制到指定地址處。 for (i=0 ; i<4 ; i++,address += BLOCK_SIZE) if (bh[i]) { wait_on_buffer(bh[i]); // 等待緩沖區(qū)解鎖(如果已被上鎖的話)。 if (bh[i]->b_uptodate) // 如果該緩沖區(qū)中數(shù)據(jù)有效的話,則復(fù)制。 COPYBLK(bh[i]->b_data,(char *)address); brelse(bh[i]); // 釋放該緩沖區(qū)。 }}/* * OK,breada 可以象bread 一樣使用,但會另外預(yù)讀一些塊。該函數(shù)參數(shù)列表
* 需要使用一個負(fù)數(shù)來表明參數(shù)列表的結(jié)束。 */
//// 從指定設(shè)備讀取指定的一些塊。
// 成功時返回第1 塊的緩沖區(qū)頭指針,否則返回NULL。struct buffer_head * breada(int dev,int first, ...){ va_list args; struct buffer_head * bh, *tmp;
// 取可變參數(shù)表中第1 個參數(shù)(塊號)。 va_start(args,first);
// 取高速緩沖中指定設(shè)備和塊號的緩沖區(qū)。如果該緩沖區(qū)數(shù)據(jù)無效,則發(fā)出讀設(shè)備數(shù)據(jù)塊請求。 if (!(bh=getblk(dev,first))) panic("bread: getblk returned NULL\n"); if (!bh->b_uptodate) ll_rw_block(READ,bh);
// 然后順序取可變參數(shù)表中其它預(yù)讀塊號,并作與上面同樣處理,但不引用。 while ((first=va_arg(args,int))>=0) { tmp=getblk(dev,first); if (tmp) { if (!tmp->b_uptodate) ll_rw_block(READA,bh); tmp->b_count--; } }
// 可變參數(shù)表中所有參數(shù)處理完畢。等待第1 個緩沖區(qū)解鎖(如果已被上鎖)。 va_end(args); wait_on_buffer(bh);
// 如果緩沖區(qū)中數(shù)據(jù)有效,則返回緩沖區(qū)頭指針,退出。否則釋放該緩沖區(qū),返回NULL,退出。 if (bh->b_uptodate) return bh; brelse(bh); return (NULL);}
//// 緩沖區(qū)初始化函數(shù)。
// 參數(shù)buffer_end 是指定的緩沖區(qū)內(nèi)存的末端。對于系統(tǒng)有16MB 內(nèi)存,則緩沖區(qū)末端設(shè)置為4MB。
// 對于系統(tǒng)有8MB 內(nèi)存,緩沖區(qū)末端設(shè)置為2MB。void buffer_init(long buffer_end){ struct buffer_head * h = start_buffer; void * b; int i;
// 如果緩沖區(qū)高端等于1Mb,則由于從640KB-1MB 被顯示內(nèi)存和BIOS 占用,因此實(shí)際可用緩沖區(qū)內(nèi)存
// 高端應(yīng)該是640KB。否則內(nèi)存高端一定大于1MB。 if (buffer_end == 1<<20) b = (void *) (640*1024); else b = (void *) buffer_end;
// 這段代碼用于初始化緩沖區(qū),建立空閑緩沖區(qū)環(huán)鏈表,并獲取系統(tǒng)中緩沖塊的數(shù)目。
// 操作的過程是從緩沖區(qū)高端開始劃分1K 大小的緩沖塊,與此同時在緩沖區(qū)低端建立描述該緩沖塊
// 的結(jié)構(gòu)buffer_head,并將這些buffer_head 組成雙向鏈表。
// h 是指向緩沖頭結(jié)構(gòu)的指針,而h+1 是指向內(nèi)存地址連續(xù)的下一個緩沖頭地址,也可以說是指向h
// 緩沖頭的末端外。為了保證有足夠長度的內(nèi)存來存儲一個緩沖頭結(jié)構(gòu),需要b 所指向的內(nèi)存塊
// 地址>= h 緩沖頭的末端,也即要>=h+1。 while ( (b = (char*)b - BLOCK_SIZE) >= ((void *) (h+1)) ) { h->b_dev = 0; // 使用該緩沖區(qū)的設(shè)備號。 h->b_dirt = 0; // 臟標(biāo)志,也即緩沖區(qū)修改標(biāo)志。 h->b_count = 0; // 該緩沖區(qū)引用計數(shù)。 h->b_lock = 0; // 緩沖區(qū)鎖定標(biāo)志。 h->b_uptodate = 0; // 緩沖區(qū)更新標(biāo)志(或稱數(shù)據(jù)有效標(biāo)志)。 h->b_wait = NULL; // 指向等待該緩沖區(qū)解鎖的進(jìn)程。 h->b_next = NULL; // 指向具有相同hash 值的下一個緩沖頭。 h->b_prev = NULL; // 指向具有相同hash 值的前一個緩沖頭。 h->b_data = (char *) b; // 指向?qū)?yīng)緩沖區(qū)數(shù)據(jù)塊(1024 字節(jié))。 h->b_prev_free = h-1; // 指向鏈表中前一項。 h->b_next_free = h+1; // 指向鏈表中下一項。
h++; // h 指向下一新緩沖頭位置。 NR_BUFFERS++; // 緩沖區(qū)塊數(shù)累加。 if (b == (void *) 0x100000) // 如果地址b 遞減到等于1MB,則跳過384KB, b = (void *) 0xA0000; // 讓b 指向地址0xA0000(640KB)處。 } h--; // 讓h 指向最后一個有效緩沖頭。 free_list = start_buffer; // 讓空閑鏈表頭指向頭一個緩沖區(qū)頭。 free_list->b_prev_free = h; // 鏈表頭的b_prev_free 指向前一項(即最后一項)。 h->b_next_free = free_list; // h 的下一項指針指向第一項,形成一個環(huán)鏈。
// 初始化hash 表(哈希表、散列表),置表中所有的指針為NULL。 for (i=0;i<NR_HASH;i++) hash_table[i]=NULL;}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -