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

聊聊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)

分享創造快樂