linux IO層以及相關的IO系統呼叫回顧

2021-06-13 12:22:19 字數 4423 閱讀 6488

linux下,i/o處理的層次可分為4層:

1、系統呼叫層,應用程式使用系統呼叫指定讀寫哪個檔案,檔案偏移是多少等等

2、檔案系統層,寫檔案時將使用者態中的buffer拷貝到核心態下,並由cache快取該部分資料

檔案系統最上方時vfs,它是應用層和具體檔案系統之間的介面,遮蔽不同檔案系統的差異,以一種統一的方式給上層呼叫。

3、塊層,管理塊裝置i/o佇列,對i/o請求進行合併、排序

在塊層下其實有乙個dm層。比如lvm,蔽了底層硬碟帶來的複雜性使得檔案系統和硬碟的關係更為靈活,可以做統一的進行磁碟管理,做動態的磁碟擴充套件,條帶化,映象,快照。

4、裝置層,通過dma與記憶體直接互動,將資料寫到磁碟

這裡先重點講一下io相關的系統呼叫,其他的層次後面再詳解

io層次的系統呼叫可以有多種方式

readahead:

需要讀取一塊資料的時候,如果後繼的操作是連續讀,可以在多讀一些資料到page cache中,這樣下次訪問的連續資料的時候,這些資料已經在page cache中了,就無需i/o操作,這樣會大大提高資料訪問的效率

buffer io的read/write:

read過程:把需要讀取得資料轉換成對應的頁,對需要讀入的每乙個頁執行如下過程:首先呼叫page_cache_readahead(如果預讀開啟),根據當前預讀的狀態和執行預讀策略(預讀狀態結構根據命中情況和讀模式動態調整,預讀策略也動態調整),預讀過程會進行i/o操作也可能不會,預讀過程完畢之後,首先檢查page cache中是否已經有所需資料,如果沒有,說明預讀沒有命中,呼叫handle_ra_miss調整預讀策略,進行i/o操作把該頁資料讀入記憶體並加入page cache,當該頁資料讀入page cache之後(或者之前就在page cache中),標記該頁mark_page_accessed,然後把該頁資料拷貝到應用程式位址空間。

write過程:和read過程一樣,需要把需要寫的資料轉換成對應頁,從應用程式位址空間把資料拷貝到對應頁,並標記該頁狀態為dirty,呼叫mark_page_accessed,如果沒有指定為同步寫,寫操作至此就返回了。如果檔案在開啟時指定了o_sync,系統會把本次寫過程所有涉及到的dirty頁回寫到塊裝置中,這個過程是阻塞的

direct io(檔案以o_direct方式開啟進行,呼叫read/write,或者是操作原始裝置):

應用程式在開啟檔案時指定了o_direct,作業系統在讀寫檔案時會完全繞過page cache,讀的時候資料直接從塊裝置傳送到應用程式指定的快取中,寫的時候資料也是直接從應用程式指定的快取中寫到塊裝置中,由於沒有經過page cache層,這種方式的寫總是同步寫。

在操作原始(raw)裝置時,也是這種方式,直接訪問原始裝置,沒有經過檔案系統cache。

o_direct 和 raw裝置最根本的區別是o_direct是基於檔案系統的,也就是在應用層來看,其操作物件是檔案控制代碼,核心和檔案層來看,其操作是基於inode和資料塊,這些概念都是和ext2/3的檔案系統相關,寫到磁碟上最終是ext3檔案。

而raw裝置寫是沒有檔案系統概念,操作的是扇區號,操作物件是扇區,寫出來的東西不一定是ext3檔案(如果按照ext3規則寫就是ext3檔案)。

一般基於o_direct來設計優化自己的檔案模組,是不滿系統的cache和排程策略,自己在應用層實現這些,來制定自己特有的業務特色檔案讀寫。但是寫出來的東西是ext3檔案,該磁碟卸下來,mount到其他任何linux系統上,都可以檢視。

而基於raw裝置的設計系統,一般是不滿現有ext3的諸多缺陷,設計自己的檔案系統。自己設計檔案布局和索引方式。舉個極端例子:把整個磁碟做乙個檔案來寫,不要索引。這樣沒有inode限制,沒有檔案大小限制,磁碟有多大,檔案就能多大。這樣的磁碟卸下來,mount到其他linux系統上,是無法識別其資料的。

兩者都要通過驅動層讀寫;在系統引導啟動,還處於實模式的時候,可以通過bios介面讀寫raw裝置。

mmap:

繞過檔案系統,mmap對映某個檔案(或者檔案的一部分)到程序的位址空間時,並沒有載入檔案的資料,而只是在程序的虛擬位址空間劃分出一塊區域,標記這塊區域用於對映到檔案的資料區域,mmap的操作就完成了。

當程序試圖讀或者寫檔案對映區域時,如果沒有對應的物理頁面,系統發生缺頁異常並進入缺頁異常處理程式,缺頁異常處理程式根據該區域記憶體的型別使用不同的策略解決缺頁。對於使用mmap對映檔案的虛擬記憶體區域,處理程式首先找到相關的檔案的管理資料結構,確定所需頁面對應的檔案偏移,此時需要從檔案中把對應資料載入到page_cache中。

「mmap與read/write兩條路線對檔案的訪問比較

無論是通過mmap方式或read/write方式訪問檔案在核心中都必須經過兩個快取:乙個是用a

ddress_space來組織的以頁為基礎的快取;乙個是以buffer來組織的快取,但實際上這兩

個快取只是同乙個緩衝池裡內容的不同組織方式。當需要從檔案讀寫內容時,都經過 add

ress_space_operation中提供的函式也就是說路徑是一致的。

如果是用read/write方式,使用者須向核心指定要讀多少,核心再把得到的內容從核心緩衝

池拷向使用者空間;寫也須要有乙個大致如此的過程。mmap的優勢在於通過把檔案的某一塊

內容對映到使用者空間上,使用者可以直接向核心緩衝池讀寫這一塊內容,這樣一來就少了內

核與使用者空間的來回拷貝所以通常更快。但 mmap方式只適用於更新、讀寫一塊固定大小的

檔案區域而不能做像諸如不斷的寫內容進入檔案導到檔案增長這類的事。

先說一下read/write系統呼叫,read/write系統呼叫會有以下的操作:

1.訪問檔案,這涉及到使用者態到核心態的轉換

2.讀取硬碟檔案中的對應資料,核心會採用預讀的方式,比如我們需要訪問100位元組,核心實際會將按照4kb(記憶體頁的大小)儲存在page cache中

3.將read中需要的資料,從page cache中拷貝到使用者緩衝區中

整個過程還是比較艱辛的,基本上涉及到使用者核心態的切換,還有就是資料拷貝接下來繼續說mmap吧,mmap系統呼叫是將硬碟檔案對映到用記憶體中,說的底層一些是將page cache中的頁直接對映到使用者程序位址空間中,從而程序可以直接訪問自身位址空間的虛擬位址來訪問page cache中的頁,這樣會並涉及page cache到使用者緩衝區之間的拷貝,mmap系統呼叫與read/write呼叫的區別在於:

1.mmap只需要一次系統呼叫,後續操作不需要系統呼叫

2.訪問的資料不需要在page cache和使用者緩衝區之間拷貝

從上所述,當頻繁對乙個檔案進行讀取操作時,mmap會比read高效一些。

不同於read,write系統呼叫的是,mmap的過程少了核心態copy資料到應用的開銷。

sendfile:

sendfile把檔案的從某個位置開始的內容送入另乙個檔案中(可能會是乙個套接字),這種操作節省了資料在記憶體中的拷貝次數,如果使用read/write實現,會增加兩次資料拷貝操作。其核心實現方法和read/write也沒有太大區別

fsync/fdatasync/msync:

這三個系統呼叫都涉及把記憶體中的dirty page同步到的塊裝置上的檔案中去,它們之間有一些區別。

fsync把檔案在page cache中的dirty page寫回到磁碟中去,乙個檔案在page cache中的內容包括檔案資料也包括inode資料,當寫乙個檔案時,除了修改檔案資料之外,也修改了inode中的資料(比如檔案修改時間),所以實際上有這兩部分的資料需要同步,fsync把和指定檔案相關的這兩種dirty page回寫到磁碟中。除了使用fsync強行同步檔案之外,系統也會定期自動同步,即把dirty page回寫到磁碟中。

fdatasync只回寫檔案資料的dirty page到磁碟中,不回寫檔案inode相關的dirty page。

msync與fsync有所不同,在使用mmap對映檔案到記憶體位址,向對映位址寫入資料時如果沒有缺頁,就不會進入核心層,也無法設定寫入頁的狀態為dirty,但cpu會自動把頁表的dirty位置位,如果不設定頁為dirty,其他的同步程式,如fsync以及核心的同步執行緒都無法同步這部分資料。msync的主要作用就是檢查乙個記憶體區域的頁表,把dirty位置位的頁表項對應的頁的狀態設定為dirty,如果msync指定了m_sync引數,msync還會和fsync一樣同步資料,如果指定為m_async,則用核心同步執行緒或其他呼叫同步資料。

在munmap時,系統會對對映的區域執行類似msync的操作,所以如果不呼叫msync資料也不一定會丟失(程序在退出時對對映區域也會自動呼叫munmap),但寫大量資料不呼叫msync會有丟失資料的風險。

LinuxI O埠和I O記憶體的訪問介面

裝置通常會提供一組暫存器來用於控制裝置 讀寫裝置和獲取裝置狀態,即控制暫存器 資料暫存器和狀態暫存器。這些暫存器可能位於i o 空間,也可能位於記憶體空間。當位於i o 空間時,通常被稱為i o埠,位於記憶體空間時,對應的記憶體空間被稱為i o 記憶體。1 i o 埠 常用介面有inb,outb,i...

網頁漂浮層的例子以及相關解釋

clientheight 都沒有什麼異議,都認為是內容可視區域的高度,也就是說頁面瀏覽器中可以看到內容的這個區域的高度,一般是最後乙個工具條以下到狀態列以上的這個區域,與頁面內容無關。offsetheight ie opera 認為 offsetheight clientheight 滾動條 邊框。...

卷積層以及池化層的輸出維度

一 輸入的四個維度 2 height weight 的高和寬。3 channels 的通道數,黑白 就是1,rgb就是3。例如我們的輸入是x 333,28,28,3 則代表我們有333個寬和高都是28的黑白 單通道 二 卷積核的四個維度 1 height weight 卷積核矩陣的維度 2 inch...