網路檔案系統快取 API

Fscache 提供了一個 API,網路檔案系統可以透過它來使用本地快取設施。該 API 圍繞許多原則進行安排

  1. 快取在邏輯上被組織成卷和卷內的資料儲存物件。

  2. 卷和資料儲存物件由各種型別的 cookie 表示。

  3. Cookie 具有鍵,用於將它們與其對等項區分開來。

  4. Cookie 具有一致性資料,允許快取確定快取的資料是否仍然有效。

  5. I/O 儘可能非同步完成。

此 API 由以下專案使用

#include <linux/fscache.h>.

概述

從網路檔案系統的角度來看,fscache 層次結構組織成兩個級別。上層表示“卷”,下層表示“資料儲存物件”。這些由兩種型別的 cookie 表示,以下稱為“卷 cookie”和“cookie”。

網路檔案系統使用卷金鑰獲取卷的卷 cookie,該金鑰表示定義該卷的所有資訊(例如,單元格名稱或伺服器地址、卷 ID 或共享名稱)。這必須呈現為可用作目錄名稱的可列印字串(即,沒有“/”字元,並且不應以“.”開頭)。最大名稱長度比檔名元件的最大大小小 1(允許快取後端為自己的目的保留一個字元)。

檔案系統通常為每個超級塊都有一個卷 cookie。

然後,檔案系統使用物件金鑰獲取該卷中每個檔案的 cookie。物件金鑰是二進位制 blob,只需要在其父卷中是唯一的。快取後端負責將二進位制 blob 呈現為它可以使用的東西,並且可以採用雜湊表、樹或任何東西來提高其查詢物件的能力。這對網路檔案系統是透明的。

檔案系統通常為每個 inode 都有一個 cookie,並且會在 iget 中獲取它,並在驅逐 cookie 時放棄它。

一旦它有了一個 cookie,檔案系統就需要將 cookie 標記為正在使用。這會導致 fscache 將快取後端傳送出去,以在後臺查詢/建立 cookie 的資源,檢查其一致性,並在必要時將物件標記為正在修改中。

檔案系統通常會在其檔案開啟例程中“使用”該 cookie,並在檔案釋放中取消使用它,並且它需要在呼叫以本地截斷 cookie 時使用該 cookie。當頁面快取變髒時,它需要使用 cookie,並在回寫完成後取消使用它。這有點棘手,並且為此做出了規定。

在對 cookie 執行讀取、寫入或調整大小操作時,檔案系統必須首先開始操作。這會將資源複製到 holding 結構中,並將額外的 pin 放入快取中,以阻止快取撤回拆除正在使用的結構。然後可以發出實際操作,並且可以在完成後檢測到衝突的失效。

預計檔案系統將使用 netfslib 訪問快取,但這實際上不是必需的,它可以直接使用 fscache I/O API。

卷註冊

網路檔案系統的第一步是獲取它想要訪問的卷的卷 cookie

struct fscache_volume *
fscache_acquire_volume(const char *volume_key,
                       const char *cache_name,
                       const void *coherency_data,
                       size_t coherency_len);

此函式建立一個卷 cookie,其中指定的卷金鑰作為其名稱,並記錄一致性資料。

卷金鑰必須是一個可列印的字串,其中沒有“/”字元。它應該以檔案系統的名稱開頭,並且長度不應超過 254 個字元。它應該唯一地表示卷,並且將與快取中儲存的內容匹配。

呼叫者還可以指定要使用的快取的名稱。如果指定,fscache 將查詢或建立該名稱的快取 cookie,並且如果該名稱的快取處於聯機狀態或變為聯機狀態,則將使用該快取。如果未指定快取名稱,它將使用手頭的第一個快取,並將名稱設定為該快取。

指定的一致性資料儲存在 cookie 中,並將與磁碟上儲存的一致性資料匹配。如果沒有提供資料,資料指標可能為 NULL。如果一致性資料不匹配,整個快取卷將失效。

如果卷金鑰已被獲取的卷使用,或者如果發生分配失敗,此函式可能會返回 EBUSY 等錯誤。如果未啟用 fscache,它也可能返回 NULL 卷 cookie。將 NULL cookie 傳遞給任何採用卷 cookie 的函式是安全的。這將導致該函式不執行任何操作。

當網路檔案系統完成卷後,它應該透過呼叫以下命令來放棄它

void fscache_relinquish_volume(struct fscache_volume *volume,
                               const void *coherency_data,
                               bool invalidate);

這將導致提交或刪除卷,並且如果密封,一致性資料將設定為提供的值。一致性資料的量必須與獲取卷時指定的長度匹配。請注意,在此卷中獲得的所有資料 cookie 必須在放棄卷之前放棄。

資料檔案註冊

一旦它有了一個卷 cookie,網路檔案系統就可以使用它來獲取資料儲存的 cookie

struct fscache_cookie *
fscache_acquire_cookie(struct fscache_volume *volume,
                       u8 advice,
                       const void *index_key,
                       size_t index_key_len,
                       const void *aux_data,
                       size_t aux_data_len,
                       loff_t object_size)

這使用指定的索引金鑰在卷中建立 cookie。索引金鑰是給定長度的二進位制 blob,並且對於卷必須是唯一的。這被儲存到 cookie 中。對其內容沒有限制,但其長度不應超過最大檔名長度的四分之三左右,以便進行編碼。

呼叫者還應該在 aux_data 中傳入一段一致性資料。將分配一個大小為 aux_data_len 的緩衝區,並將一致性資料複製到其中。假設大小隨時間推移是不變的。一致性資料用於檢查快取中資料的有效性。提供了可用於更新一致性資料的函式。

還應該提供被快取物件的檔案大小。這可能用於修剪資料,並將與一致性資料一起儲存。

此函式永遠不會返回錯誤,儘管它可能會在分配失敗或如果未啟用 fscache 時返回 NULL cookie。傳入 NULL 卷 cookie 並將返回的 NULL cookie 傳遞給任何採用它的函式是安全的。這將導致該函式不執行任何操作。

當網路檔案系統完成 cookie 後,它應該透過呼叫以下命令來放棄它

void fscache_relinquish_cookie(struct fscache_cookie *cookie,
                               bool retire);

這將導致 fscache 提交支援 cookie 的儲存或刪除它。

調整資料檔案大小(截斷)

如果網路檔案系統檔案透過截斷在本地調整大小,則應呼叫以下命令來通知快取

void fscache_resize_cookie(struct fscache_cookie *cookie,
                           loff_t new_size);

呼叫者必須首先將 cookie 標記為正在使用。cookie 和新大小被傳入,並且快取同步調整大小。預計這將在 inode 鎖下的 ->setattr() inode 操作中呼叫。

資料 I/O API

要直接透過 cookie 執行資料 I/O 操作,可以使用以下函式

int fscache_begin_read_operation(struct netfs_cache_resources *cres,
                                 struct fscache_cookie *cookie);
int fscache_read(struct netfs_cache_resources *cres,
                 loff_t start_pos,
                 struct iov_iter *iter,
                 enum netfs_read_from_hole read_hole,
                 netfs_io_terminated_t term_func,
                 void *term_func_priv);
int fscache_write(struct netfs_cache_resources *cres,
                  loff_t start_pos,
                  struct iov_iter *iter,
                  netfs_io_terminated_t term_func,
                  void *term_func_priv);

begin 函式設定操作,將所需的資源附加到 cookie 中的快取資源塊。假設它沒有返回錯誤(例如,如果給定 NULL cookie,它將返回 -ENOBUFS,但否則不執行任何操作),則可以發出其他兩個函式之一。

readwrite 函式啟動直接 I/O 操作。兩者都採用先前設定的快取資源塊、起始檔案位置的指示以及描述緩衝區並指示資料量的 I/O 迭代器。

read 函式還採用一個引數來指示它應如何處理磁碟內容中部分填充的區域(孔)。這可能是忽略它、跳過初始孔並在緩衝區中放置零或給出錯誤。

可以為讀取和寫入函式提供一個可選的終止函式,該函式將在完成後執行

typedef
void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error,
                              bool was_async);

如果給出了終止函式,則操作將非同步執行,並且終止函式將在完成後被呼叫。如果未給出,則操作將同步執行。請注意,在非同步情況下,操作有可能在函式返回之前完成。

讀取和寫入函式都在完成時結束操作,分離任何固定的資源。

如果在操作進行時發生失效,則讀取操作將失敗,並顯示 ESTALE。

資料檔案一致性

要請求更新 cookie 上的一致性資料和檔案大小,應呼叫以下命令

void fscache_update_cookie(struct fscache_cookie *cookie,
                           const void *aux_data,
                           const loff_t *object_size);

這將更新 cookie 的一致性資料和/或檔案大小。

資料檔案失效

有時需要使包含資料的物件失效。通常,當伺服器通知網路檔案系統遠端第三方更改時,這是必要的 - 此時,檔案系統必須丟棄它擁有的檔案狀態和快取資料,並從伺服器重新載入。

要指示應使快取物件失效,應呼叫以下命令

void fscache_invalidate(struct fscache_cookie *cookie,
                        const void *aux_data,
                        loff_t size,
                        unsigned int flags);

這將增加 cookie 中的失效計數器,以導致未完成的讀取失敗,並顯示 -ESTALE,根據提供的資訊設定一致性資料和檔案大小,阻止 cookie 上的新 I/O,並排程快取以擺脫舊資料。

失效在工作執行緒中非同步執行,因此它不會阻塞太多。

回寫資源管理

要從網路檔案系統回寫將資料寫入快取,需要在進行修改時(例如,當頁面被標記為髒時)固定所需的快取資源,因為無法在退出的執行緒中開啟檔案。

提供了以下工具來管理此操作

  • 提供了一個 inode 標誌 I_PINNING_FSCACHE_WB,用於指示已為此 inode 的 cookie 上保留了一個正在使用。只有在持有 inode 鎖時才能更改它。

  • 如果 __writeback_single_inode() 清除 I_PINNING_FSCACHE_WB,因為所有髒頁面都被清除,則一個標誌 unpinned_fscache_wb 被放置在 writeback_control 結構中。

為了支援這一點,提供了以下函式

bool fscache_dirty_folio(struct address_space *mapping,
                         struct folio *folio,
                         struct fscache_cookie *cookie);
void fscache_unpin_writeback(struct writeback_control *wbc,
                             struct fscache_cookie *cookie);
void fscache_clear_inode_writeback(struct fscache_cookie *cookie,
                                   struct inode *inode,
                                   const void *aux);

set 函式旨在從檔案系統的 dirty_folio 地址空間操作中呼叫。如果未設定 I_PINNING_FSCACHE_WB,它會設定該標誌並增加 cookie 上的使用計數(呼叫者必須已經呼叫了 fscache_use_cookie())。

unpin 函式旨在從檔案系統的 write_inode 超級塊操作中呼叫。它透過在 writeback_control 結構中設定了 unpinned_fscache_wb 時取消使用 cookie 來在寫入後清理。

clear 函式旨在從 netfs 的 evict_inode 超級塊操作中呼叫。必須在 truncate_inode_pages_final()之後呼叫它,但在 clear_inode()之前呼叫它。這會清理任何懸掛的 I_PINNING_FSCACHE_WB。它還允許更新一致性資料。

本地修改的快取

如果網路檔案系統具有要在快取中寫入的本地修改的資料,則需要標記頁面以指示正在進行寫入,並且如果已經存在標記,則需要等待它首先被刪除(大概是由於已經在進行中的操作)。這可以防止多個競爭的 DIO 寫入到快取中的同一儲存。

首先,netfs 應該透過執行類似以下的操作來確定快取是否可用

bool caching = fscache_cookie_enabled(cookie);

如果要嘗試快取,則應等待頁面,然後使用 netfs 幫助程式庫提供的以下函式標記頁面

void set_page_fscache(struct page *page);
void wait_on_page_fscache(struct page *page);
int wait_on_page_fscache_killable(struct page *page);

標記 span 中的所有頁面後,netfs 可以要求 fscache 安排寫入該區域

void fscache_write_to_cache(struct fscache_cookie *cookie,
                            struct address_space *mapping,
                            loff_t start, size_t len, loff_t i_size,
                            netfs_io_terminated_t term_func,
                            void *term_func_priv,
                            bool caching)

並且如果在到達該點之前發生錯誤,可以透過呼叫以下命令來刪除標記

void fscache_clear_page_bits(struct address_space *mapping,
                             loff_t start, size_t len,
                             bool caching)

在這些函式中,傳入指向源頁面所附加的對映的指標,並且 start 和 len 指示將要寫入的區域的大小(它不必與頁面邊界對齊,但必須與支援檔案系統上的 DIO 邊界對齊)。caching 引數指示是否應跳過快取,如果為 false,則這些函式不執行任何操作。

write 函式採用一些額外的引數:cookie 表示要寫入的快取物件,i_size 指示 netfs 檔案的大小,term_func 指示一個可選的完成函式,term_func_priv 以及錯誤或寫入量將傳遞給該函式。

請注意,write 函式將始終非同步執行,並在呼叫 term_func 之前取消標記所有頁面。

頁面釋放和失效

Fscache 會跟蹤我們是否已經為我們剛剛建立的快取物件快取了任何資料。它知道在執行寫入之前,它不必執行任何讀取操作,然後它寫入的頁面已被 VM 釋放,之後它必須在快取中查詢。

為了通知 fscache 頁面現在可能在快取中,應該從 release_folio 地址空間操作中呼叫以下函式

void fscache_note_page_release(struct fscache_cookie *cookie);

如果頁面已被釋放(即 release_folio 返回 true)。

頁面釋放和頁面失效也應該等待頁面上留下的任何標記,以說明正在從該頁面進行 DIO 寫入

void wait_on_page_fscache(struct page *page);
int wait_on_page_fscache_killable(struct page *page);

API 函式參考

struct fscache_volume *fscache_acquire_volume(const char *volume_key, const char *cache_name, const void *coherency_data, size_t coherency_len)

將卷註冊為需要快取服務

引數

const char *volume_key

卷的標識字串

const char *cache_name

要使用的快取的名稱(如果使用預設值,則為 NULL)

const void *coherency_data

要檢查的任意一致性資料(如果為 NULL)

size_t coherency_len

一致性資料的大小

描述

如果快取服務可用,則將卷註冊為需要快取服務。呼叫者必須為卷提供識別符號,並且還可以指示它應該位於哪個快取中。如果在快取中找到預先存在的卷條目,則一致性資料必須匹配,否則該條目將失效。

成功時返回 cookie 指標,如果記憶體不足則返回 -ENOMEM,如果該名稱的快取卷已被獲取,則返回 -EBUSY。請注意,“NULL”是一個有效的 cookie 指標,如果拒絕快取,則可以返回該指標。

void fscache_relinquish_volume(struct fscache_volume *volume, const void *coherency_data, bool invalidate)

停止快取卷

引數

struct fscache_volume *volume

卷 cookie

const void *coherency_data

要設定的任意一致性資料(如果為 NULL)

bool invalidate

如果應使卷失效,則為 True

描述

指示檔案系統不再需要卷的快取服務。呼叫者必須在呼叫此命令之前放棄所有檔案 cookie。儲存的一致性資料已更新。

獲取 cookie 以表示快取物件

引數

struct fscache_volume *volume

在其中查詢/建立此 cookie 的卷

u8 advice

建議標誌 (FSCACHE_COOKIE_ADV_*)

const void *index_key

此 cookie 的索引金鑰

size_t index_key_len

索引金鑰的大小

const void *aux_data

cookie 的輔助資料(可能為 NULL)

size_t aux_data_len

輔助資料緩衝區的大小

loff_t object_size

物件的初始大小

描述

獲取 cookie 以表示給定快取卷中的資料檔案。

有關完整說明,請參見網路檔案系統快取 API

請求使用附加到物件的 cookie

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

bool will_modify

如果預計在本地修改快取

描述

請求使用附加到物件的 cookie。如果物件的記憶體即將被本地修改,則呼叫者應告知快取,然後快取可以應用已設定為處理此情況的策略。

停止使用附加到物件的 cookie

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

const void *aux_data

更新的輔助資料(如果為 NULL)

const loff_t *object_size

物件的修改大小(如果為 NULL)

描述

停止使用附加到物件的 cookie。當用戶計數達到零時,將允許繼續放棄 cookie。

將 cookie 返回到快取,可能會丟棄它

引數

struct fscache_cookie *cookie

正在返回的 cookie

bool retire

如果要丟棄 cookie 表示的快取物件,則為 True

描述

此函式將 cookie 返回到快取,如果將 retire 設定為 true,則強制丟棄關聯的快取物件。

有關完整說明,請參見網路檔案系統快取 API

請求更新快取物件

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

const void *aux_data

cookie 的更新輔助資料(可能為 NULL)

const loff_t *object_size

物件的當前大小(可能為 NULL)

描述

請求更新與 cookie 關聯的快取物件的索引資料。如果設定了 aux_data,則將首先更新 cookie 上的輔助資料,如果設定了 object_size,則將更新物件大小,並且可能修剪物件。

有關完整說明,請參見網路檔案系統快取 API

請求調整快取物件的大小

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

loff_t new_size

物件的新大小(可能為 NULL)

描述

請求更改物件的大小。

有關完整說明,請參見網路檔案系統快取 API

void fscache_invalidate(struct fscache_cookie *cookie, const void *aux_data, loff_t size, unsigned int flags)

通知快取物件需要失效

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

const void *aux_data

cookie 的更新輔助資料(可能為 NULL)

loff_t size

物件的修訂大小。

unsigned int flags

失效標誌 (FSCACHE_INVAL_*)

描述

通知快取物件需要失效,並且應該中止正在快取上執行的任何檢索或儲存操作。 這會增加 cookie 上的 inval_counter,呼叫者可以使用它來重新考慮完成的 I/O 請求。

如果 flags 設定了 FSCACHE_INVAL_DIO_WRITE,則表示這是由於直接 I/O 寫入導致的,並將導致在此 cookie 上停用快取,直到完全未使用為止。

有關完整說明,請參見網路檔案系統快取 API

const struct netfs_cache_ops *fscache_operation_valid(const struct netfs_cache_resources *cres)

如果操作資源可用,則返回 true

引數

const struct netfs_cache_resources *cres

要檢查的資源。

描述

如果可用,則返回操作表的指標;如果不可用,則返回 NULL。

int fscache_begin_read_operation(struct netfs_cache_resources *cres, struct fscache_cookie *cookie)

為 netfs 庫開始讀取操作

引數

struct netfs_cache_resources *cres

正在執行的讀取操作的快取資源

struct fscache_cookie *cookie

表示快取物件的 cookie

描述

代表 netfs 輔助庫開始讀取操作。 cres 指示操作狀態應附加到的快取資源; cookie 指示將被訪問的快取物件。

cres->inval_countercookie->inval_counter 設定,以便在操作結束時進行比較。 這允許呼叫者檢測操作期間的失效。

返回

  • 0 - 成功

  • -ENOBUFS
    • 沒有可用的快取

  • 快取中的其他錯誤程式碼,例如 -ENOMEM。

void fscache_end_operation(struct netfs_cache_resources *cres)

結束 netfs 庫的讀取操作

引數

struct netfs_cache_resources *cres

讀取操作的快取資源

描述

在讀取請求結束時清理資源。

int fscache_read(struct netfs_cache_resources *cres, loff_t start_pos, struct iov_iter *iter, enum netfs_read_from_hole read_hole, netfs_io_terminated_t term_func, void *term_func_priv)

開始從快取讀取。

引數

struct netfs_cache_resources *cres

要使用的快取資源

loff_t start_pos

快取檔案中的起始檔案偏移量

struct iov_iter *iter

要填充的緩衝區 - 以及長度

enum netfs_read_from_hole read_hole

如何處理資料中的空洞。

netfs_io_terminated_t term_func

完成時要呼叫的函式

void *term_func_priv

term_func 的私有資料

描述

開始從快取讀取。 cres 指示要從中讀取的快取物件,並且必須事先透過呼叫 fscache_begin_operation() 獲得。

資料被讀入迭代器 iter,這也指示了操作的大小。 start_pos 是檔案中的起始位置,但如果適當地設定了 seek_data,則快取可以使用 SEEK_DATA 查詢下一段資料,並將空洞寫入迭代器。

在操作終止時,將呼叫 term_func 並提供 term_func_priv 以及寫入的資料量(如果成功),否則提供錯誤程式碼。

read_hole 指示應如何處理快取中部分填充的區域。 它可以是以下設定之一:

NETFS_READ_HOLE_IGNORE - 嘗試讀取(可能返回短讀)。

NETFS_READ_HOLE_FAIL - 如果遇到空洞,則給出 ENODATA。

int fscache_begin_write_operation(struct netfs_cache_resources *cres, struct fscache_cookie *cookie)

為 netfs 庫開始寫入操作

引數

struct netfs_cache_resources *cres

正在執行的寫入操作的快取資源

struct fscache_cookie *cookie

表示快取物件的 cookie

描述

代表 netfs 輔助庫開始寫入操作。 cres 指示操作狀態應附加到的快取資源; cookie 指示將被訪問的快取物件。

cres->inval_countercookie->inval_counter 設定,以便在操作結束時進行比較。 這允許呼叫者檢測操作期間的失效。

返回

  • 0 - 成功

  • -ENOBUFS
    • 沒有可用的快取

  • 快取中的其他錯誤程式碼,例如 -ENOMEM。

int fscache_write(struct netfs_cache_resources *cres, loff_t start_pos, struct iov_iter *iter, netfs_io_terminated_t term_func, void *term_func_priv)

開始寫入快取。

引數

struct netfs_cache_resources *cres

要使用的快取資源

loff_t start_pos

快取檔案中的起始檔案偏移量

struct iov_iter *iter

要寫入的資料 - 以及長度

netfs_io_terminated_t term_func

完成時要呼叫的函式

void *term_func_priv

term_func 的私有資料

描述

開始寫入快取。 cres 指示要寫入的快取物件,並且必須事先透過呼叫 fscache_begin_operation() 獲得。

要寫入的資料從迭代器 iter 獲取,這也指示了操作的大小。 start_pos 是檔案中的起始位置。

在操作終止時,將呼叫 term_func 並提供 term_func_priv 以及寫入的資料量(如果成功),否則提供錯誤程式碼。

void fscache_clear_page_bits(struct address_space *mapping, loff_t start, size_t len, bool caching)

從一組頁面中清除 PG_fscache 位

引數

struct address_space *mapping

要用作源的 netfs inode

loff_t start

mapping 中的起始位置

size_t len

要解鎖的資料量

bool caching

如果已設定 PG_fscache

描述

從一系列頁面中清除 PG_fscache 標誌,並喚醒任何正在等待的人。

void fscache_write_to_cache(struct fscache_cookie *cookie, struct address_space *mapping, loff_t start, size_t len, loff_t i_size, netfs_io_terminated_t term_func, void *term_func_priv, bool using_pgpriv2, bool caching)

將寫入儲存到快取並清除 PG_fscache

引數

struct fscache_cookie *cookie

表示快取物件的 cookie

struct address_space *mapping

要用作源的 netfs inode

loff_t start

mapping 中的起始位置

size_t len

要寫回的資料量

loff_t i_size

inode 的新大小

netfs_io_terminated_t term_func

完成時要呼叫的函式

void *term_func_priv

term_func 的私有資料

bool using_pgpriv2

如果我們使用 PG_private_2 標記正在進行的寫入

bool caching

如果我們真的想進行快取

描述

netfs 的輔助函式,用於將髒資料從 inode 寫入支援它的快取物件中。

startlen 描述了資料的範圍。 這不需要是頁面對齊的,但為了滿足 DIO 要求,快取可能會將其擴充套件到任一端的頁面邊界。 覆蓋該範圍的所有頁面都必須用 PG_fscache 標記。

如果給定,term_func 將在完成後被呼叫,並提供 term_func_priv。 請注意,如果設定了 using_pgpriv2,則 PG_private_2 標誌此時已被清除,因此 netfs 必須保留其自身在對映上的 pin。

void fscache_note_page_release(struct fscache_cookie *cookie)

注意 netfs 頁面已釋放

引數

struct fscache_cookie *cookie

與檔案對應的 cookie

描述

請注意,已複製到快取的頁面已釋出。 這意味著將來的讀取需要檢視快取以檢視它是否存在。