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