Android核心技術—核心(Linux) 的IO棧
theme: smartblue
簡述
Linux的IO路徑可能是Linux系統中最紛繁複雜的模組了,而它又是如此的重要,直接決定了系統的效能。 接下來我們來看一張熟悉的老圖:
由圖可見,從系統呼叫的介面再往下,Linux下的IO棧致大致有幾個層次:
應用程式:
這沒什麼好說的,通過相關係統呼叫(如open/read/write)發起IO請求,屬於IO請求的源頭;
檔案系統:
應用程式的請求直接到達檔案系統層。檔案系統又分為VFS和具體檔案系統(ext3、ext4等),VFS對應用層提供統一的訪問介面,而ext3等檔案系統則具體實現了這些介面。另外,為了提供IO效能,在該層還實現了諸如page cache等功能。同時,使用者也可以選擇繞過page cache,而是直接使用direct模式進行IO(如資料庫)。
塊裝置層:
檔案系統將IO請求打包提交給塊裝置層,該層會對這些IO請求作合併、排序、排程等,然後以新的格式發往更底層。在該層次上實現了多種電梯排程演算法,如cfq、deadline等。
SCSI層:
塊裝置層將請求發往SCSI層,SCSI就開始真實處理這些IO請求,但是SCSI層又對其內部按照功能劃分了不同層次: * SCSI高層:高層驅動負責管理disk,接收塊裝置層發出的IO請求,打包成SCSI層可識別的命令格式,繼續往下發; * SCSI中層:中層負責通用功能,如錯誤處理,超時重試等; * SCSI低層:底層負責識別物理裝置,將其抽象提供給高層,同時接收高層派發的scsi命令,交給物理裝置處理。
各層介面
清晰的介面能讓複雜的系統變得容易理解和維護。
應用程式 => 檔案系統
做開發的人可能都應該瞭解,通過諸如open/read/pread/write/writev等POSIX介面來呼叫檔案系統各種功能。由於其普遍性,在這裡就不一一描述介面形式了。
檔案系統 => 塊裝置層
這裡我們將檔案系統當成一個整體,並不區分VFS和具體檔案系統。塊裝置層對檔案系統提供的介面為submit_bio(),介面形式如下:
void submit_bio(int rw, struct bio *bio)
檔案系統向塊裝置提交的每個bio請求都設定了完成回撥函式,記錄在bio->bi_end_io。bio請求完成後,通過該欄位通知檔案系統。
塊裝置層 => SCSI上層
scsi_reuqest_fn()和struct request_queue。 老實來說,塊裝置層和SCSI上層之間分的沒有那麼清楚,耦合的稍微緊密,塊裝置層看到的IO請求結構是request。而SCSI層看到的IO命令則是scsi_cmnd。
每個scsi裝置(如scsi disk)均維護了一個請求佇列request_queue,而每個scsi裝置對上層呈現的其實是一個塊裝置。因此,塊裝置和scsi裝置有著天然的聯絡,request_queue則是連線塊裝置層和SCSI層的紐帶。塊裝置層對request請求最終會派發至request_queue中。而在特定條件下通過洩流機制將request_queue中積攢的request派發至SCSI層處理。而洩流的實際處理過程就是scsi_request_fn()函式,因此說它是塊裝置層和SCSI上層的介面也不為過,雖然不是特別準確。在scsi_reuqest_fn內會進行request至scsi_cmnd的轉換。
SCSI上層 => SCSI中間層
SCSI上層在收到塊裝置層發起的scsi命令後馬不停蹄又將其轉發至SCSI中間層。SCSI上層至SCSI中間層的介面是 scsi_dispatch_cmd
static void scsi_request_fn(struct request_queue *q) {
......
// 設定scsi命令完成回撥函式
cmd->scsi_done = scsi_done;
rtn = scsi_dispatch_cmd(cmd);
......
}
SCSI中間層 => SCSI低層
SCSI中間層收到塊裝置層發下來的scsi_cmnd命令後,中間層作自己處理後,然後再將該命令繼續往下傳遞,接下來該命令到了scsi底層,而傳遞的介面是 queuecommand()
static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) {
......
rtn = host->hostt->queuecommand(host, cmd);
......
}
host為該裝置所屬的主機介面卡結構。任何一個SCSI主機介面卡都需要實現queuecommand介面。注意這個提交過程是非同步的,無需等待該命令完成便直接返回。 scsi 命令完成後,會通過記錄在命令內
linux io棧(讀寫流程)
linux IO 儲存棧分為7層:
VFS 虛擬檔案層: 在各個具體的檔案系統上建立一個抽象層,遮蔽不同檔案系統的差異。 PageCache 層: 為了緩解核心與磁碟速度的巨大差異。 對映層 Mapping Layer: 核心必須從塊裝置上讀取資料,Mapping layer 要確定在物理裝置上的位置。 通用塊層: 通用塊層處理來自系統其他元件發出
讀流程
- (1)系統呼叫read()會觸發相應的VFS(Virtual Filesystem Switch)函式,傳遞的引數 有檔案描述符和檔案偏移量。
- (2)VFS確定請求的資料是否已經在記憶體緩衝區中;若資料不在記憶體中,確定如何執行讀 操作。
- (3)假設核心必須從塊裝置上讀取資料,這樣核心就必須確定資料在物理裝置上的位置。 這由對映層(Mapping Layer)來完成。
- (4)此時核心通過通用塊裝置層(Generic Block Layer)在塊裝置上執行讀操作,啟動I/O 操作,傳輸請求的資料。
- (5)在通用塊裝置層之下是I/O排程層(I/O Scheduler Layer),根據核心的排程策略,對 等待的I/O等待佇列排序。
- (6)最後,塊裝置驅動(Block Device Driver)通過向磁碟控制器傳送相應的命令,執行 真正的資料傳輸。
寫流程
write()—>sys_write()—>vfs_write()—>通用塊層—>IO排程層—>塊裝置驅動層—>塊裝置
塊裝置
系統中能夠隨機訪問固定大小資料片(chunk)的裝置稱為塊裝置,這些資料片就稱作 塊。最常見的塊裝置是硬碟,除此之外,還有CD-ROM驅動器和SSD等。它們通常安裝文 件系統的方式使用。
有關Android開發中的核心(Linux) 的IO棧學習,這裡就做一部分淺析,如需深入瞭解或其他問題可以點下方連結
傳送直達↓↓↓ docs.qq.com/doc/DUkNRVF…
總結
- IO 棧:VFS - 檔案系統 - 塊層 - SCSI 驅動層;
- VFS 負責通用的檔案抽象語義,管理並切換檔案系統;
- 檔案系統負責抽象出“檔案的概念”,維護“檔案”資料到塊層的位置對映,怎麼擺放資料,怎麼抽象檔案都是檔案系統說了算;
- 塊層對底層硬體裝置做一層統一的抽象,最重要的是做一些IO 排程的策略。比如,儘可能收集批量 IO 聚合下發,讓 IO 儘可能的順序,合併 IO 請求減少 IO 次數等等;
- SCSI 層則是負責最後對硬體磁碟的對接,驅動層,本質就是個翻譯器;
- 檔案的 buffer write 要實現 .write_begin,.write_page 等介面,前者用於分配 page 並繫結塊層物理空間,後者使用者非同步回刷的時候呼叫(注意,非常規的優化在回刷的時候才去繫結物理空間);
- 檔案系統 .write_begin 呼叫分配物理位置的時候依賴於get_block的實現,物理位置分配好之後,page 會對應到特定的 buffer head 結構,buffer head 結構則對應到具體的塊裝置位置;
- direct IO 直接在使用者路徑上刷資料到磁碟,不走 PageCache 的邏輯,但並不是所有檔案系統都會實現它。
- Android效能優化——記憶體洩漏的根本原因
- Android ViewStub的使用方法——邊走邊看邊學
- Android進階——sdk開發和apk開發有什麼區別?
- Android開發——RXBinding防抖機制與案件分析
- Android效能啟動優化——IO優化進階
- Android適配【入坑指南 解決痛點】
- android 開發——疑難雜症ANR簡單介紹與解析
- Android外掛化框架—— Atlas
- 一名合格的音影片工程師,技能樹狀分佈是怎樣形成的?
- Android核心技術—核心(Linux) 的IO棧
- Android前沿技術—— Jetpack Compose
- Android開發資料結構與演算法——ArrayList原始碼講解
- Flutter中如何構建顯式動畫 【教學】
- Android記憶體抖動(主要原因分析 6個優化小技巧)
- Android車載多媒體開發——MediaSession框架
- 車機空調系統開發(HVAC),溫暖一整個冬天!
- 大廠為什麼在招聘安卓架構師時,為啥都需要熟悉 framework 經驗?
- 一個擴充套件性極強的 Flutter MVVM 實用框架,完善你的技術棧
- 2021年,跨端是否已成趨勢?Android 開發還有必要學 Flutter 嗎?
- Jetpack的MVVM通訊 - LiveData的原理分析