1. 程式人生 > >(萊昂氏unix原始碼分析導讀-35)快取管理(上)

(萊昂氏unix原始碼分析導讀-35)快取管理(上)

                                                                               by cszhao1980

系統定義了NBUF個快取區域,每個514個位元組:

4720: char buffers[NBUF][514];

【注】:514個位元組稍稍大於一個物理盤塊的size,多出的2byte的用途不明。

而“快取頭”陣列buf[NBUF]的每個entry對應一個快取區域,其b_addr被設定為對應的快取區

的首地址,如:&buffers[1]。對於快取的使用都是通過其快取頭陣列entry來完成。

【思考題】:為什麼這裡可以直接使用邏輯地址,如:&buffers[1]

Unix使用兩種(帶頭結點的)雙向迴圈連結串列(佇列)來管理這些快取,即

(1)         AV佇列:即空閒佇列,對首為buf bfreelist

(2)         B佇列:即裝置的任務佇列,對首為某裝置(devtab型別)。

顯然,可以有多個b佇列。

【注】:在b隊列當中,對首是devtab型別,而成員都是buf型別。該連結串列得以形成的原因是兩種類

型都用同名的成員(b_forwb_back)作為前後指標,而且,它們的這兩種struct中的位置是相同的。

總的原則是,空閒的快取將掛在AV佇列中,當需要操作某裝置時就從AV佇列中取下,掛到該

裝置的b佇列中,而裝置操作完成後,又重新將其放還到AV

佇列中。

系統的某些實現使這一過程顯得有些晦澀:

(1)         在裝置操作完成後,會將快取放回到AV佇列,但沒有將該快取從原裝置的b佇列中取

下來——這一步是在再次分配該快取時完成的。即在分配快取時,分為3

i.           AV佇列中取下;

ii.          從原裝置佇列中取下;

iii.        掛到新裝置佇列中。

(2)         問題來了,在系統初啟階段,所有快取都沒有分配過裝置,那麼其“原裝置佇列”在哪?

                 為解決這一問題,系統定義了一個特殊的裝置佇列——空閒裝置佇列,其裝置號為-1,其

                  首指標為我們的老朋友buf freelist

之所以會採用這樣的設計,是為了支援“延遲寫”技術,以提高效率。所謂“延遲寫”即寫入快取

的內容不會馬上被寫入磁碟——真正的寫入是在使用者程式或“定時”程式呼叫flush時完成的。

(1)         要支援“延遲寫”,快取必須仍掛在裝置佇列中,否則磁碟內容就會丟失;

(2)         如果直到真正寫入後,快取才可以釋放回AV佇列,有可能造成快取資源緊張;

所以系統採用了這樣的方式:

(1)         一旦對快取的寫入結束,該快取即釋放入AV佇列,但其flag設定了B_DELWRI標誌;

(2)         如果該快取被再次分配,會檢查器B_DELWRI標誌,如其置位,則首先執行寫入,再

                   將此快取分配給新裝置。