深入理解磁盤文件訪問

Disk-file-io

讀寫磁盤數據是程序設計中最基本也是最重要的操作之一。實際系統爲磁盤 I/O 提供了多種接口,不同的接口不但語義有所不同,而且性能也有差異。理解這些接口對實現正確和高效的程序是很重要的,本文將結合內核的實現原理來比較各種磁盤 I/O 系統調用,希望能從最底層來透徹理解這些接口。

 

目錄

 

1 內核訪問磁盤文件的原理

2 訪問磁盤數據的系統調用比較

2.1 read/write 系統調用

2.2 mmap 系統調用

2.3 直接讀寫磁盤設備文件

2.4 Direct I/O

 

1 內核訪問磁盤文件的原理

 

Linux 內核訪問磁盤文件的大體原理如圖所示。

內核數據結構

內核會爲每個進程關聯一個到 file 結構的指針數組,我們熟悉的文件描述符是這個數組的下標值,數組中每個元素指向一個 file 結構,一個 file 結構代表這個進程打開的一個文件。file 結構中有一個到 inode 結構的指針(注意,這裏的 inode 是一個在內存中結構,而不是保存在磁盤上的 inode),在內核中,每一個 inode 唯一標識一個文件,因此,如果同時有多個進程打開同一個文件,他們的 file 結構指向同一個 inode。inode 結構中有一個到 page cache 結構的指針,內核爲每個文件單獨維護一個 page cache,用戶進程對文件的大多數讀寫操作實際上都只是直接作用在 page cache 上面,內核會在適當的時機將 page cache 中的內容寫回到磁盤上,這樣能夠大大減少訪問磁盤的次數,從而提高系統性能。

page cache 是 Linux 內核文件訪問過程中至關重要的數據結構,我們需要再瞭解一些關於它的細節。page cache 中保存了用戶進程訪問過的該文件的內容,這些內容以頁爲單位保存在內存中,當用戶需要訪問文件的某個偏移量上的數據時,內核會以偏移量爲索引,找到相應的內存頁,如果該頁還沒有讀入內存,則需要訪問磁盤讀取數據。爲了提高搜索頁的速度同時節省 page cache 數據結構佔用的空間,Linux 內核使用基樹(radix tree)來保存 page cache 中的頁。

 

2 訪問磁盤數據的系統調用比較

 

在瞭解了內核訪問磁盤文件的原理之後,我們來比較各種訪問磁盤數據的方法。

2.1 read/write 系統調用

這是最常用、最基本的文件訪問方法,它們的使用方法相信讀者已經比較熟悉,就不作介紹了。這對系統調用涉及兩個額外的開銷:系統調用開銷和數據複製開銷。每訪問一次文件,都需要產生一次系統調用,但是現在的處理器系統調用的開銷通常是比較小的;數據需要在用戶的緩衝區和 page cache 之間進行復制。

2.2 mmap 系統調用

mmap 系統調用的原理是將 page cache 中的頁直接映射到用戶進程的地址空間中去,從而進程可以通過訪問自身地址空間中的虛擬地址來訪問 page cache 中的頁,當然,最後還是需要依靠內核在適當的時候將 page cache 中的內容寫回到磁盤。所以,mmap 和 read/write 之間的區別在於只需映射一次,後續的訪問無須系統調用;數據不需要在用戶緩衝區和 page cache 之間複製。

需要特別注意的是,對同一個文件而言,mmap 所訪問的和 read/write 訪問的是同一個 page cache。

mmap 的原型如下

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

其中 addr 是映射的起始虛擬地址,一般指定爲 NULL,這樣內核會自動選擇合適的地址並作爲結果返回給用戶。

另一個比較重要的參數是 flags,它可以取兩個值, 分別爲 MAP_SHARED 和 MAP_PRIVATE。如果指定爲 MAP_SHARED 用戶對映射的內存區域的更改會反映在 page cache 上,這樣所有讀寫這個文件的進程相當於共享這片內存區域(read/write 操作也是作用在這個 page cache 上的);如果指定爲 MAP_PRIVATE,當用戶修改這片內存區域的時候,內核會複製相應的頁(Copy On Write),用戶的更改只會作用在這些複製出來的頁上,而不是作用在 page cache 中,這樣其他訪問這個文件的進程就不會看到該文件的更改。

使用 mmap 可以提高訪問文件的速度,但是這個操作會爲內核引入額外的維護開銷(需要維護更多的地址空間結構)。通常如果需要訪問整個比較大的結構化的二進制文件,使用 mmap 可以提高訪問的效率,而且便於編程。

 

2.3 直接讀寫磁盤設備文件

 

還有一種不太常用的訪問磁盤數據的方法是繞開文件系統,直接讀寫磁盤設備文件(如 /dev/sda1)。但是從內核的實現來看,這種操作的效率並不比普通的 read/write 系統調用高,因爲內核爲磁盤設備文件單獨維護一個 page cache,所有讀寫操作依然需要經過數據複製。

 

2.4 Direct I/O

 

Direct I/O 的意思是用戶進程的讀寫操作不經過 page cache,而是直接寫入磁盤。使用 Direct I/O 的最常見程序是數據庫,由於數據庫系統通常會實現自己的緩存策略,所以 page cache 的緩存對它來說是多餘的,而且會影響效率。要使用 direct I/O 只需要在打開文件的時候設置 O_DIRECT 標誌位,或者使用 fcntl 系統調用來設置該標誌位。

 

原文地址:http://www.gonggeng.org/mediawiki/index.php/Disk-file-io

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章