Fiemap Ioctl

fiemap ioctl 是使用者空間獲取檔案範圍對映的一種有效方法。 與逐塊對映(如 bmap)不同,fiemap 返回範圍列表。

請求基礎

fiemap 請求在 struct fiemap 中編碼

struct fiemap

檔案範圍對映

定義:

struct fiemap {
    __u64 fm_start;
    __u64 fm_length;
    __u32 fm_flags;
    __u32 fm_mapped_extents;
    __u32 fm_extent_count;
    struct fiemap_extent fm_extents[];
};

成員

fm_start

開始對映的位元組偏移量(包括)(輸入)

fm_length

使用者空間所需的對映的邏輯長度(輸入)

fm_flags

請求的 FIEMAP_FLAG_* 標誌(輸入/輸出)

fm_mapped_extents

已對映的範圍數(輸出)

fm_extent_count

fm_extents 陣列的大小(輸入)

fm_extents

對映的範圍陣列(輸出)

fm_start 和 fm_length 指定程序需要對映的檔案中的邏輯範圍。 返回的範圍反映磁碟上的範圍 - 也就是說,第一個返回範圍的邏輯偏移量可能在 fm_start 之前開始,最後一個返回範圍覆蓋的範圍可能在 fm_length 之後結束。 所有偏移量和長度均以位元組為單位。

可以在 fm_flags 中設定某些標誌來修改查詢對映的方式。 如果核心不理解某些特定標誌,它將返回 EBADR,並且 fm_flags 的內容將包含導致錯誤的標誌集。 如果核心與傳遞的所有標誌相容,則 fm_flags 的內容將保持不變。 使用者空間需要確定拒絕特定標誌對其操作是否是致命的。 此方案旨在允許 fiemap 介面在未來增長,而不會失去與舊軟體的相容性。

fm_extent_count 指定 fm_extents[] 陣列中可用於返回範圍的元素數量。 如果 fm_extent_count 為零,則 fm_extents[] 陣列將被忽略(不會返回任何範圍),並且 fm_mapped_extents 計數將儲存 fm_extents[] 中儲存檔案當前對映所需的範圍數。 請注意,沒有任何東西可以阻止檔案在呼叫 FIEMAP 之間發生更改。

以下標誌可以在 fm_flags 中設定

FIEMAP_FLAG_SYNC

如果設定了此標誌,核心將在對映範圍之前同步檔案。

FIEMAP_FLAG_XATTR

如果設定了此標誌,則返回的範圍將描述 inode 的擴充套件屬性查詢樹,而不是其資料樹。

FIEMAP_FLAG_CACHE

此標誌請求快取範圍。

範圍對映

範圍資訊在嵌入的 fm_extents 陣列中返回,使用者空間必須與 fiemap 結構一起分配該陣列。 fiemap_extents[] 陣列中的元素數量應透過 fm_extent_count 傳遞。 核心對映的範圍數將透過 fm_mapped_extents 返回。 如果分配的 fiemap_extents 數小於對映請求範圍所需的數量,則可以在 fm_extent[] 陣列中對映的最大範圍數將返回,並且 fm_mapped_extents 將等於 fm_extent_count。 在這種情況下,陣列中的最後一個範圍將不會完成請求的範圍,並且不會設定 FIEMAP_EXTENT_LAST 標誌(請參閱有關範圍標誌的下一節)。

每個範圍都由單個 fiemap_extent 結構描述,如 fm_extents 中返回的

struct fiemap_extent

一個 fiemap 範圍的描述

定義:

struct fiemap_extent {
    __u64 fe_logical;
    __u64 fe_physical;
    __u64 fe_length;
    __u32 fe_flags;
};

成員

fe_logical

檔案中範圍的位元組偏移量

fe_physical

磁碟上範圍的位元組偏移量

fe_length

此範圍的位元組長度

fe_flags

此範圍的 FIEMAP_EXTENT_* 標誌

所有偏移量和長度均以位元組為單位,並反映磁碟上的偏移量和長度。 範圍的邏輯偏移量可以在請求之前開始,或者其邏輯長度可以擴充套件到請求之後,這是有效的。 除非返回 FIEMAP_EXTENT_NOT_ALIGNED,否則 fe_logical、fe_physical 和 fe_length 將與檔案系統的塊大小對齊。 除了標記為 FIEMAP_EXTENT_MERGED 的範圍外,相鄰的範圍不會合並。

fe_flags 欄位包含描述返回範圍的標誌。 特殊標誌 FIEMAP_EXTENT_LAST 始終在檔案的最後一個範圍上設定,以便進行 fiemap 呼叫的程序可以確定何時沒有更多範圍可用,而無需再次呼叫 ioctl。

某些標誌是有意模糊的,並且始終在存在其他更具體的標誌時設定。 這樣,尋找一般屬性的程式不必知道所有現有和未來的標誌,這些標誌意味著該屬性。

例如,如果設定了 FIEMAP_EXTENT_DATA_INLINE 或 FIEMAP_EXTENT_DATA_TAIL,則還將設定 FIEMAP_EXTENT_NOT_ALIGNED。 尋找內聯或尾部打包資料的程式可以鎖定特定標誌。 但是,僅僅不希望嘗試對未對齊範圍進行操作的軟體可以鎖定 FIEMAP_EXTENT_NOT_ALIGNED,而不必擔心所有現在和將來的可能暗示未對齊資料的標誌。 請注意,相反的情況並非如此 - FIEMAP_EXTENT_NOT_ALIGNED 單獨出現是有效的。

FIEMAP_EXTENT_LAST

這通常是檔案中的最後一個範圍。 嘗試對映超出此範圍可能會返回空值。 某些實現設定此標誌以指示此範圍是使用者查詢的範圍中的最後一個(透過 fiemap->fm_length)。

FIEMAP_EXTENT_UNKNOWN

此範圍的位置當前未知。 這可能表明資料儲存在無法訪問的捲上,或者尚未為該檔案分配儲存空間。

FIEMAP_EXTENT_DELALLOC

這也將設定 FIEMAP_EXTENT_UNKNOWN。

延遲分配 - 雖然此範圍存在資料,但尚未分配其物理位置。

FIEMAP_EXTENT_ENCODED

此範圍不包含普通檔案系統塊,而是經過編碼(例如,加密或壓縮)。 透過 I/O 讀取到塊裝置中的此範圍的資料將具有未定義的結果。

請注意,嘗試透過寫入指示的位置來就地更新資料,而無需檔案系統的幫助,或者在使用 FIEMAP 介面返回的資訊訪問資料時,始終是未定義的,而檔案系統已掛載。 換句話說,使用者應用程式只能在檔案系統解除安裝時透過 I/O 讀取到塊裝置的範圍資料,並且只有在 FIEMAP_EXTENT_ENCODED 標誌已清除的情況下; 在任何其他情況下,使用者應用程式都不得嘗試透過塊裝置讀取或寫入檔案系統。

FIEMAP_EXTENT_DATA_ENCRYPTED

這也將設定 FIEMAP_EXTENT_ENCODED 此範圍中的資料已由檔案系統加密。

FIEMAP_EXTENT_NOT_ALIGNED

不能保證範圍偏移量和長度已對齊到塊。

FIEMAP_EXTENT_DATA_INLINE

這也將設定 FIEMAP_EXTENT_NOT_ALIGNED 資料位於元資料塊中。

FIEMAP_EXTENT_DATA_TAIL

這也將設定 FIEMAP_EXTENT_NOT_ALIGNED 資料與來自其他檔案的資料打包到一個塊中。

FIEMAP_EXTENT_UNWRITTEN

未寫入範圍 - 已分配該範圍,但其資料尚未初始化。 這表明如果透過檔案系統讀取範圍的資料將全部為零,但如果直接從裝置讀取,則內容是未定義的。

FIEMAP_EXTENT_MERGED

當檔案不支援範圍時,將設定此標誌,即,它使用基於塊的定址方案。 由於為使用者空間中的每個塊返回一個範圍將非常低效,因此核心將嘗試將大多數相鄰塊合併為“範圍”。

FIEMAP_EXTENT_SHARED

設定此標誌以請求與其他檔案共享空間。

VFS -> 檔案系統實現

希望支援 fiemap 的檔案系統必須在其 inode_operations 結構上實現 ->fiemap 回撥。 fs ->fiemap 呼叫負責定義其支援的 fiemap 標誌集,並在每個發現的範圍上呼叫一個幫助器函式

struct inode_operations {
     ...

     int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
                   u64 len);

->fiemap 傳遞 struct fiemap_extent_info,它描述了 fiemap 請求

struct fiemap_extent_info

對檔案系統的 fiemap 請求

定義:

struct fiemap_extent_info {
    unsigned int fi_flags;
    unsigned int fi_extents_mapped;
    unsigned int fi_extents_max;
    struct fiemap_extent __user *fi_extents_start;
};

成員

fi_flags

從使用者傳遞的標誌

fi_extents_mapped

對映的範圍數

fi_extents_max

fiemap_extent 陣列的大小

fi_extents_start

fiemap_extent 陣列的開頭

檔案系統不應直接訪問此結構的任何部分。 檔案系統處理程式應容忍訊號,並在收到致命訊號後返回 EINTR。

標誌檢查應透過 fiemap_prep() 幫助程式在 ->fiemap 回撥的開頭完成

int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo,
                u64 start, u64 *len, u32 supported_flags);

struct fieinfo 應作為從 ioctl_fiemap() 收到的內容傳入。 檔案系統理解的 fiemap 標誌集應透過 fs_flags 傳遞。 如果 fiemap_prep 發現無效的使用者標誌,它會將錯誤值放置在 fieinfo->fi_flags 中,並返回 -EBADR。 如果檔案系統從 fiemap_prep() 收到 -EBADR,它應立即退出,並將該錯誤返回給 ioctl_fiemap()。 此外,範圍針對支援的最大檔案大小進行驗證。

對於請求範圍中的每個範圍,檔案系統應呼叫幫助程式函式 fiemap_fill_next_extent()

int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical,
                            u64 phys, u64 len, u32 flags, u32 dev);

fiemap_fill_next_extent() 將使用傳遞的值來填充 fm_extents 陣列中的下一個空閒範圍。 代表呼叫檔案系統自動從特定標誌設定“常規”範圍標誌,以便不會破壞使用者空間 API。

fiemap_fill_next_extent() 成功時返回 0,當用戶提供的 fm_extents 陣列已滿時返回 1。 如果在將範圍複製到使用者記憶體時遇到錯誤,將返回 -EFAULT。