Linux核心學習筆記之高速緩衝管理(五)

2021-06-20 07:01:15 字數 3309 閱讀 2946

上節我們已經介紹過高速緩衝區的一些內容,為了解決記憶體磁碟的資料互動效率問題,作業系統引入了高速緩衝塊,其儲存介質是記憶體,大小和磁碟盤塊一樣為1k。

首先我們來看下高速緩衝區在記憶體中的位置

然後我們來看下在呼叫buffer_init初始化後這段黃色記憶體的樣子(其中緩衝區低端就是上面的end,緩衝區高階就是上面的4m位置,0.11是2m)

下面我們就對著這幅圖來解讀buffer_init函式

void buffer_init(void)

h--;

free_list = start_buffer;

free_list->b_prev_free = h;

h->b_next_free = free_list;

for (i=0;i

for迴圈之前的**:首先將指向緩衝塊頭部的h指標指向核心**尾部end,然後將高速緩衝塊指標b指向高速緩衝末端

(0.11是2m,這邊圖裡面是4m),當高速緩衝塊的起始位址大於緩衝塊頭部的結束位址(兩個塊沒有交集),說明可以形成一對對映(上圖乙個粉紅色塊和乙個淡綠色塊為一對對映),第一對對映就是上圖中最高最長的那條線,高速緩衝塊頭部陣列元素相互之間形成雙向鍊錶(上圖粉紅色的部分),最後free_list指向高速緩衝塊頭部陣列的第乙個元素,並使雙向鍊錶變成迴圈雙向鍊錶。

①為什麼要使用頭部和資料區分開的結構設計呢?把緩衝區頭部和緩衝資料區合併在一起不好嗎?我覺得linus是出於程式設計方便和執行效率考慮的(我在意淫作者的中心思想~),如果合併到一起,不僅沒法使用h+1這種操作了,而每次都要判斷下乙個緩衝結構頭部是不是在640k-1m之間,判斷是否相等比判斷大小速度是差很多的,而且原本1m-2m之間正好是整數倍個緩衝塊資料區,如果和頭部合併,那就不是整數倍,不僅前半段會有記憶體浪費,後半段也有浪費(上圖綠色部分),所以這種劃分是最節省記憶體的辦法,而且管理資訊放在一起,也比較好管理

②粉紅色塊已經是陣列了,為什麼還要用迴圈雙向鍊錶弄起來?注意這是初始化的情況,當從磁碟讀入緩衝塊後,就會出現一部分使用,一部分未使用狀態的緩衝塊,為了能快速索引到能使用的空閒塊,所以需要對這些塊進行排序,將占用態的放到佇列末尾,但是陣列實現這個操作效率太慢,而使用迴圈雙向鍊錶的話就簡單多了。為什麼不像i節點一樣用位圖?我覺得是由於能對映多少對高速緩衝結構一開始並不知道,無法預先設定好位圖大小,所以這邊沒法用點陣圖來指明空閒塊情況,不過個人覺得還是可以設定乙個大點的點陣圖,然後在初始化的時候計算對映對的個數並儲存起來。

for迴圈實現的是高速緩衝塊頭部指標陣列hash_table的初始化,它儲存的是占用態的高速緩衝塊頭部,它的作用需要結合高速緩衝塊的使用來理解,請看下文~

①我們先看下buffer_init完成之後記憶體中的資料結構(上面的就是hash_table,它是指向緩衝塊頭部的指標陣列,目前都是懸空的;下面就是緩衝塊頭部陣列/雙向鍊錶,其中上面的雙向指標是配合hash_table使用的,用於處理hash值相同的情況,下面的就是用於形成自身迴圈雙向鍊錶結構的指標,高速緩衝塊頭部結構我們已經在初始化 的while迴圈裡面看過了,紫色的表示當前free_list指向的頭部結構)

這邊我簡要說下獲取高速緩衝塊的getblk函式流程,就是找到乙個分紅色結點,然後將其從hash_table的雙向鍊錶和頭部陣列的迴圈雙向鍊錶中取下來,然後在完成設定後,將已變為藍色占用態的頭部放回兩個鍊錶的過程,詳細流程圖見下面的殘卷三,這邊將**其中最重要的兩個步驟remove_from_queues和insert_into_queues

②為裝置號為dev盤塊號為block的磁碟盤塊獲取乙個高速緩衝塊過程,這裡假設hash(dev,block)==0

這是執行remove_from_queues後高速緩衝結構的樣子,注意紫色已經移到下乙個頭部(free_list),陣列的第乙個元素已經變成了占用態

這是執行

insert_into_queues後高速緩衝結構的樣子,我們會發現頭部陣列的第乙個元素已經被放回迴圈雙向佇列中了,不過現在它不再是鏈首而是鏈尾了;我們發現hash_table[0]的指標已經指向了占用態頭部(不過我覺得這部分原始碼好像有問題,最後不應該要先判斷下next指標指向不為空才能使用其指向的結構的prev指標嗎?)

②為裝置號為dev2盤塊號為block2的磁碟盤塊獲取乙個高速緩衝塊過程,這裡假設

hash(dev2,block2)==0,這邊主要是為了演示高速緩衝塊頭部的上面的雙向鍊錶指標的作用,所以故意設定本次的hash值還是0

這是執行

remove_from_queues後高速緩衝結構的樣子,和上面一樣,就不多做解釋了

這是執行

insert_into_queues後高速緩衝結構的樣子,有木有看到頭部結構上面的雙向指標的變化,他們自己形成了乙個雙向鍊錶,而hash_table[0]則指向鏈首了,之所以這邊要用雙鏈而不是單鏈,主要是高速緩衝塊釋放的順序不同,所以要能支援任意位置的節點的刪除操作,而雙向鍊錶最擅長處理刪除操作了。

對比起複雜的空閒緩衝塊申請操作,緩衝塊釋放操作就簡單多了,直接減少緩衝塊的引用計數就可以了。那這些鍊錶結構誰來清理?很簡單,下次申請到此高速緩衝塊的程序負責清理工作,而且如果緩衝塊是髒的,還得負責寫回磁碟,現在知道我們申請的時候為什麼要先解除安裝下來節點,然後再放回鍊錶裡面吧?所以只有第一次用的才是爽的,後面的程序想用都要先幫前面的程序擦乾淨屁股~

這部分c**用流程**釋起來比較清楚(個人覺得難理解的地方也加了評注),

最後我們再看下記憶體磁碟資料互動的函式之間的層次關係為:

<1>read(),write()

<2>block_read(),block_write(),file_read(),file_write(),read_pipe(),write()

<3>bread()或 breada()

<4>getblk()

<5>ll_rw_block()

linux核心學習筆記

核心的配置 a.make s3c2410 deconfig b.make menuconfig 圖形化配置 c.使用廠家給出的配置 生成.config 編譯生成核心,使用如下命令 make vmlinux make uimage 帶頭部 真正核心 1 config 建立生成autoconf.h 供源...

Linux核心學習筆記

2.2 核心原始碼樹 arch 特定體系結構的原始碼 block crypto api crypto 核心原始碼文件 drivers 裝置驅動程式 firmware fs vfs和各種檔案系統 include 核心標頭檔案 init 核心引導和初始化 ipc 程序間通訊 kernel 像排程程式這樣...

Linux核心學習筆記 核心同步

linux核心中執行的程式,時刻都要防止併發引起的競態。這將會導致資料結構被破壞,嚴重的時候會引起核心崩潰。所以核心同步技術對核心開發的驅動程式來說非常重要。不懂核心同步技術的人,是寫不出安全健壯的核心驅動程式來的。在學習核心同步技術之前需要掌握一下幾個概念。1 並行,併發與競態 在smp執行的li...