顯式易失性回寫快取控制

介紹

許多儲存裝置,尤其是在消費市場中,都帶有易失性回寫快取。這意味著裝置在資料實際到達非易失性儲存之前,就向作業系統發出 I/O 完成訊號。 這種行為顯然加快了各種工作負載,但這意味著當作業系統執行資料完整性操作(如 fsync、sync 或解除安裝)時,需要強制將資料重新整理到非易失性儲存。

Linux 塊層提供了兩種簡單的機制,允許檔案系統控制儲存裝置的快取行為。 這些機制是強制快取重新整理和請求的強制單元訪問 (FUA) 標誌。

顯式快取重新整理

可以將 REQ_PREFLUSH 標誌 OR 到從檔案系統提交的 bio 的 r/w 標誌中,這將確保在實際 I/O 操作開始之前,儲存裝置的易失性快取已被重新整理。 這明確保證了先前完成的寫入請求在標記的 bio 啟動之前已存在於非易失性儲存上。 此外,可以在其他方面為空的 bio 結構上設定 REQ_PREFLUSH 標誌,這隻會導致顯式快取重新整理,而沒有任何依賴的 I/O。 建議使用 blkdev_issue_flush() 輔助函式來進行純快取重新整理。

強制單元訪問

可以將 REQ_FUA 標誌 OR 到從檔案系統提交的 bio 的 r/w 標誌中,這將確保僅在資料已提交到非易失性儲存後才發出此請求的 I/O 完成訊號。

檔案系統的實現細節

檔案系統可以簡單地設定 REQ_PREFLUSH 和 REQ_FUA 位,而不必擔心底層裝置是否需要任何顯式快取重新整理以及強制單元訪問的實現方式。 REQ_PREFLUSH 和 REQ_FUA 標誌都可以設定在單個 bio 上。

塊驅動程式的特性設定

對於不支援易失性寫快取的裝置,不需要驅動程式支援,塊層在進入驅動程式之前完成空的 REQ_PREFLUSH 請求,並從具有有效負載的請求中刪除 REQ_PREFLUSH 和 REQ_FUA 位。

對於具有易失性寫快取的裝置,驅動程式需要透過設定以下內容來告訴塊層它支援重新整理快取

BLK_FEAT_WRITE_CACHE

queue_limits 特性欄位中的標誌。 對於也支援 FUA 位的裝置,還需要告訴塊層傳遞 REQ_FUA 位,方法是在 queue_limits 結構的特性欄位中也設定

BLK_FEAT_FUA

標誌。

基於 bio 的塊驅動程式的實現細節

對於基於 bio 的驅動程式,如果驅動程式設定了 BLK_FEAT_WRITE_CACHE 標誌,則 REQ_PREFLUSH 和 REQ_FUA 位將簡單地傳遞給驅動程式,並且驅動程式需要處理它們。

注意:當 _未_ 設定 BLK_FEAT_FUA 標誌時,也會傳遞 REQ_FUA 位。 任何設定 BLK_FEAT_WRITE_CACHE 的基於 bio 的驅動程式也需要處理 REQ_FUA。

對於重新對映驅動程式,REQ_FUA 位需要傳播到底層裝置,並且需要為設定了 REQ_PREFLUSH 位的 bio 實現全域性重新整理。

blk-mq 驅動程式的實現細節

當設定 BLK_FEAT_WRITE_CACHE 標誌時,帶有有效負載的 REQ_OP_WRITE | REQ_PREFLUSH 請求會自動轉換為 REQ_OP_FLUSH 請求序列,然後是塊層的實際寫入。

當設定 BLK_FEAT_FUA 標誌時,REQ_FUA 位會簡單地傳遞給 REQ_OP_WRITE 請求;否則,在完成寫入請求後,塊層會為設定了 REQ_FUA 位的 bio 提交發送 REQ_OP_FLUSH 請求。