檔案的直接訪問¶
動機¶
頁面快取通常用於緩衝檔案的讀寫操作。它也用於提供透過呼叫 mmap 對映到使用者空間的頁面。
對於類似記憶體的塊裝置,頁面快取頁將是不必要的原始儲存副本。DAX 程式碼透過直接對儲存裝置執行讀寫操作來刪除額外的副本。 對於檔案對映,儲存裝置直接對映到使用者空間。
用法¶
如果您有一個支援 DAX 的塊裝置,您可以像往常一樣在其上建立檔案系統。 DAX 程式碼目前僅支援塊大小等於核心 PAGE_SIZE 的檔案,因此您可能需要在建立檔案系統時指定塊大小。
目前有 5 個檔案系統支援 DAX:ext2、ext4、xfs、virtiofs 和 erofs。 在它們上面啟用 DAX 的方式不同。
在 ext2 和 erofs 上啟用 DAX¶
掛載檔案系統時,在命令列中使用 -o dax 選項,或者將“dax”新增到 /etc/fstab 中的選項。 這適用於啟用檔案系統中所有檔案的 DAX。 它相當於下面的 -o dax=always 行為。
在 xfs 和 ext4 上啟用 DAX¶
總結¶
存在一個核心檔案訪問模式標誌 S_DAX,它對應於 statx 標誌 STATX_ATTR_DAX。 有關此訪問模式的詳細資訊,請參見 statx(2) 的手冊頁。
存在一個持久標誌 FS_XFLAG_DAX,可以應用於常規檔案和目錄。 此建議標誌可以隨時設定或清除,但是這樣做不會立即影響 S_DAX 狀態。
如果在目錄上設定了持久 FS_XFLAG_DAX 標誌,則所有後續在該目錄中建立的常規檔案和子目錄都將繼承此標誌。 在父目錄上設定或清除此標誌時,已經存在的檔案和子目錄不會被父目錄的此修改所修改。
存在可以覆蓋 FS_XFLAG_DAX 以設定 S_DAX 標誌的 dax 掛載選項。 鑑於底層儲存支援 DAX,以下情況成立
-o dax=inode表示“遵循 FS_XFLAG_DAX”,這是預設值。
-o dax=never表示“從不設定 S_DAX,忽略 FS_XFLAG_DAX。”
-o dax=always表示“始終設定 S_DAX,忽略 FS_XFLAG_DAX。”
-o dax是一箇舊版選項,它是dax=always的別名。警告
選項
-o dax將來可能會被刪除,因此-o dax=always是指定此行為的首選方法。注意
即使使用 dax 選項掛載檔案系統,對 FS_XFLAG_DAX 的修改和繼承行為仍保持不變。 但是,核心 inode 狀態 (S_DAX) 將被覆蓋,直到使用 dax=inode 重新掛載檔案系統,並且 inode 從核心記憶體中逐出。
可以透過以下方式更改 S_DAX 策略
在建立檔案之前,根據需要設定父目錄 FS_XFLAG_DAX
設定適當的 dax=”foo” 掛載選項
更改現有常規檔案和目錄上的 FS_XFLAG_DAX 標誌。 這具有執行時約束和限制,在下面的 6) 中進行了描述。
當透過切換持久 FS_XFLAG_DAX 標誌來更改 S_DAX 策略時,對現有常規檔案的更改只有在檔案被所有程序關閉後才會生效。
詳細資訊¶
每個檔案有兩個 dax 標誌。 一個是持久 inode 設定 (FS_XFLAG_DAX),另一個是表示該功能活動狀態的易失標誌 (S_DAX)。
FS_XFLAG_DAX 保留在檔案系統中。 可以使用 FS_IOC_FS`[`GS]`ETXATTR` ioctl (請參見 ioctl_xfs_fsgetxattr(2)) 或諸如 'xfs_io' 的實用程式來設定、清除和/或查詢此持久配置設定。
新檔案和目錄在建立時自動從其父目錄繼承 FS_XFLAG_DAX。 因此,在目錄建立時設定 FS_XFLAG_DAX 可用於設定整個子樹的預設行為。
為了闡明繼承,這裡有 3 個示例
示例 A
mkdir -p a/b/c
xfs_io -c 'chattr +x' a
mkdir a/b/c/d
mkdir a/e
------[outcome]------
dax: a,e
no dax: b,c,d
示例 B
mkdir a
xfs_io -c 'chattr +x' a
mkdir -p a/b/c/d
------[outcome]------
dax: a,b,c,d
no dax:
示例 C
mkdir -p a/b/c
xfs_io -c 'chattr +x' c
mkdir a/b/c/d
------[outcome]------
dax: c,d
no dax: a,b
當檔案 inode 由核心在記憶體中例項化時,將設定當前啟用狀態 (S_DAX)。 它的設定基於底層介質支援、FS_XFLAG_DAX 的值以及檔案系統的 dax 掛載選項。
statx 可用於查詢 S_DAX。
注意
只有常規檔案會設定 S_DAX,因此 statx 永遠不會指示在目錄上設定了 S_DAX。
即使底層介質不支援 dax 和/或檔案系統被掛載選項覆蓋,也會發生設定 FS_XFLAG_DAX 標誌(專門或透過繼承)的操作。
在 virtiofs 上啟用 DAX¶
virtiofs 上 DAX 的語義基本上與 ext4 和 xfs 上的語義相同,除了當指定 '-o dax=inode' 時,virtiofs 客戶端透過 FUSE 協議從 virtiofs 伺服器派生提示是否應啟用 DAX,而不是持久 FS_XFLAG_DAX 標誌。 也就是說,是否應啟用 DAX 完全由 virtiofs 伺服器確定,而 virtiofs 伺服器本身可以部署各種演算法來做出此決定,例如,取決於主機上的持久 FS_XFLAG_DAX 標誌。
仍然支援在 guest 內部設定或清除持久 FS_XFLAG_DAX 標誌,但不保證隨後將為相應的檔案啟用或停用 DAX。 guest 內部的使用者仍然需要呼叫 statx(2) 並檢查 statx 標誌 STATX_ATTR_DAX,以檢視是否為此檔案啟用了 DAX。
塊驅動程式編寫者的實施技巧¶
要在塊驅動程式中支援 DAX,請實現“direct_access”塊裝置操作。 它用於將扇區號(以 512 位元組扇區為單位表示)轉換為頁幀號 (pfn),該頁幀號標識記憶體的物理頁。 它還會返回可用於訪問記憶體的核心虛擬地址。
direct_access 方法採用一個“size”引數,該引數指示請求的位元組數。 該函式應返回可以在該偏移量處連續訪問的位元組數。 如果發生錯誤,它也可能返回一個負的 errno。
為了支援此方法,CPU 必須始終可以按位元組訪問儲存。 如果您的裝置使用分頁技術透過較小的視窗公開大量的記憶體,則無法實現 direct_access。 同樣,如果您的裝置偶爾會長時間阻止 CPU,您也不應嘗試實現 direct_access。
以下塊裝置可用作靈感來源: - brd:RAM 支援的塊裝置驅動程式 - pmem:NVDIMM 持久記憶體驅動程式
檔案系統編寫者的實施技巧¶
檔案系統支援包括
透過在 i_flags 中設定 S_DAX 標誌來新增將 inode 標記為 DAX 的支援
實現使用
dax_iomap_rw()的 ->read_iter 和 ->write_iter 操作(當 inode 設定了 S_DAX 標誌時)為 DAX 檔案實現 mmap 檔案操作,該操作在 VMA 上設定 VM_MIXEDMAP 和 VM_HUGEPAGE 標誌,並將 vm_ops 設定為包括 fault、pmd_fault、page_mkwrite、pfn_mkwrite 的處理程式。 這些處理程式可能應該呼叫
dax_iomap_fault(),傳遞適當的 fault 大小和 iomap 操作。呼叫
iomap_zero_range()傳遞適當的 iomap 操作,而不是block_truncate_page()用於 DAX 檔案確保讀取、寫入、截斷和頁面錯誤之間有足夠的鎖定
用於分配塊的 iomap 處理程式必須確保在將分配的塊返回之前將其清零並轉換為已寫入的範圍,以避免透過 mmap 暴露未初始化的資料。
以下檔案系統可用作靈感來源
另請參見
ext2:請參見 The Second Extended Filesystem
另請參見
xfs:請參見 The SGI XFS Filesystem
另請參見
ext4:請參見 Documentation/filesystems/ext4/
處理介質錯誤¶
libnvdimm 子系統儲存每個 pmem 塊裝置的已知介質錯誤位置的記錄(在 gendisk->badblocks 中)。 如果我們在這樣的位置發生故障,或者在尚未發現的潛在錯誤的情況下,應用程式可以期望收到 SIGBUS。 Libnvdimm 還允許透過簡單地寫入受影響的扇區來清除這些錯誤(透過 pmem 驅動程式,並且如果底層 NVDIMM 支援 ACPI 定義的 clear_poison DSM)。
由於 DAX IO 通常不會透過 driver/bio 路徑,因此應用程式或系統管理員可以選擇透過以下方式從先前的 backup/inbuilt 冗餘中恢復丟失的資料
刪除受影響的檔案,然後從備份中恢復(系統管理員路線):這將釋放檔案正在使用的檔案系統塊,並且下次分配它們時,它們將首先被清零,這透過驅動程式發生,並將清除壞扇區。
截斷或打孔檔案中具有壞塊的部分(至少必須對齊的整個扇區進行打孔,但不一定是整個檔案系統塊)。
這些是允許 DAX 檔案系統在存在介質錯誤的情況下繼續執行的兩個基本路徑。 將來可以在此基礎上構建更強大的錯誤恢復機制,例如,涉及透過 DM 在塊層提供的冗餘/映象,或者另外,在檔案系統級別提供冗餘/映象。 這些必須依賴於上述兩個原則,即可以透過驅動程式傳送 IO 或清零(也透過驅動程式)來清除錯誤。
缺點¶
即使核心或其模組儲存在支援 DAX 的檔案系統上(該檔案系統位於支援 DAX 的塊裝置上),它們仍將被複制到 RAM 中。
DAX 程式碼在具有虛擬對映快取的體系結構(例如 ARM、MIPS 和 SPARC)上無法正常工作。
當沒有“struct page”來描述這些頁面時,對已從 DAX 檔案 mmapped 的使用者記憶體範圍呼叫 get_user_pages() 將失敗。 透過新增對驅動程式控制下的頁面的可選 struct page 支援,已經在某些裝置驅動程式中解決了此問題(有關如何執行此操作的示例,請參見 drivers/nvdimm 中的 CONFIG_NVDIMM_PFN)。 在非 struct page 情況下,從非 DAX 檔案對這些記憶體範圍執行 O_DIRECT 讀取/寫入將失敗
注意
O_DIRECT 讀取/寫入 DAX 檔案可以正常工作,關鍵是正在訪問的記憶體。 在非 struct page 情況下無法工作的其他內容包括 RDMA、sendfile() 和 splice()。