核心中用到的最小定址單元是塊,塊是檔案系統的一種抽象,只能基於塊來訪問檔案系統。雖然物理磁碟定址是按照扇區進行的,但核心執行的所有磁碟操作都是通過塊來執行的。塊的大小必須是扇區大小的2的整數倍(可以包含多個扇區),並且要小於頁面的大小。
2.6核心塊I/O設計到兩個結構體,struct buffer_head和struct bio。當一個塊被調入記憶體中,它要儲存在一個緩衝區中,每個緩衝區與一個塊對應,它相當於磁碟塊在記憶體中的表示,該緩衝區用buffer_head結構來表示,該結構體在2.6核心中只扮演一個描述符的作用,說明從緩衝區到磁碟塊的映射關係,不再設計到相關的塊I/O操作。
從2.6開始核心為塊I/O操作設計了一個輕量級容器,結構體struct bio.關鍵地區如下:
struct bio {
....
struct bio *bi_next; //請求鏈表
struct bio_vec *bi_io_vec; //bio_io_vec指向bio_vec結構體鏈表,bio_vec結構定義了一個特定I/O操作所需要的全部片段,每個bio_vec都是一個形式為<page,offset,len>的向量,它描述了一個特定的片段:片段所在的物理頁,塊在物理頁上的位移,從給定位移位置開始的塊長度。整個bio_vec鏈表結合起來代表一個完整的緩衝區,其各個組成部分可以是連續的也可以分散開,成為聚散向量。
unsigned short bi_index;//索引當前bi_io_vec指向的bio_vec結構體
unsigned short bi_vcnt;//描述bi_io_vec指向的bio_vec向量數目。
...
}
struct bi_vec {
struct page *bv_page;
unsigned int len;
unsigned int offset;
};
所以,每一個塊I/O請求都通過一個bio結構體來表示。每個請求包含一個或多個塊,這些Block Storage在struct bio_vec結構體鏈表中。這些結構體描述每個片段在物理頁中實際位置,並且像向量一樣被阻止起來。I/O操作的第一個片段是bi_io_vec的指向,其他片段在其後依次放置,共有bi_vcnt個片段。當塊I/O層執行請求時,需要使用各個片段時,通過bi_index來進行更新。
緩衝區頭buffer_head和bio之間存在明顯差別,bio結構體代表I/O操作,它可以包含一個或多個物理頁面;而buffer_head代表一個緩衝區,它描述的僅僅是磁碟的一個塊。因為緩衝區頭關聯的是單獨頁中的單獨磁碟塊,所以它可能會引起不必要的分割,將請求按塊為單位劃分。而bio則不是,通過向量集組織,它描述的塊可以不需要連續的儲存區。
核心通過這兩種機構分別儲存各自的資訊,可以使每種結構包含的資訊儘可能少。