歡迎光臨
每天分享高質量文章

聊聊Linux IO(中)——Linux內核中的IO棧

接上一篇聊聊Linux IO先上一張全貌圖[4]:

由圖可見,從系統呼叫的接口再往下,Linux下的IO棧致大致有三個層次:

  1. 檔案系統層,以 write(2) 為例,內核拷貝了write(2)引數指定的用戶態資料到檔案系統Cache中,並適時向下層同步

  2. 塊層,管理塊設備的IO佇列,對IO請求進行合併、排序(還記得操作系統課程學習過的IO調度演算法嗎?)

  3. 設備層,通過DMA與記憶體直接交互,完成資料和具體設備之間的交互

結合這個圖,想想Linux系統編程里用到的Buffered IOmmap(2)Direct IO,這些機制怎麼和Linux IO棧聯繫起來呢?上面的圖有點複雜,我畫一幅簡圖,把這些機制所在的位置添加進去:

這下一目瞭然了吧?傳統的Buffered IO使用read(2)讀取檔案的過程什麼樣的?假設要去讀一個冷檔案(Cache中不存在),open(2)打開檔案內核後建立了一系列的資料結構,接下來呼叫read(2),到達檔案系統這一層,發現Page Cache中不存在該位置的磁盤映射,然後創建相應的Page Cache並和相關的扇區關聯。然後請求繼續到達塊設備層,在IO佇列里排隊,接受一系列的調度後到達設備驅動層,此時一般使用DMA方式讀取相應的磁盤扇區到Cache中,然後read(2)拷貝資料到用戶提供的用戶態buffer中去(read(2)的引數指出的)。

整個過程有幾次拷貝?從磁盤到Page Cache算第一次的話,從Page Cache到用戶態buffer就是第二次了。而mmap(2)做了什麼?mmap(2)直接把Page Cache映射到了用戶態的地址空間里了,所以mmap(2)的方式讀檔案是沒有第二次拷貝過程的。那Direct IO做了什麼?這個機制更狠,直接讓用戶態和塊IO層對接,直接放棄Page Cache,從磁盤直接和用戶態拷貝資料。好處是什麼?寫操作直接映射行程的buffer到磁盤扇區,以DMA的方式傳輸資料,減少了原本需要到Page Cache層的一次拷貝,提升了寫的效率。對於讀而言,第一次肯定也是快於傳統的方式的,但是之後的讀就不如傳統方式了(當然也可以在用戶態自己做Cache,有些商用資料庫就是這麼做的)。

除了傳統的Buffered IO可以比較自由的用偏移+長度的方式讀寫檔案之外,mmap(2)Direct IO均有資料按頁對齊的要求,Direct IO還限制讀寫必須是底層儲存設備塊大小的整數倍(甚至Linux 2.4還要求是檔案系統邏輯塊的整數倍)。所以接口越來越底層,換來錶面上的效率提升的背後,需要在應用程式這一層做更多的事情。所以想用好這些高級特性,除了深刻理解其背後的機制之外,也要在系統設計上下一番功夫。

(未完)

赞(0)

分享創造快樂