缓存后端 API

FS-Cache 系统提供了一个 API,通过该 API,可以将实际缓存提供给 FS-Cache,然后由 FS-Cache 将其提供给网络文件系统和其他感兴趣的各方。此 API 由以下方面使用

#include <linux/fscache-cache.h>.

概述

与 API 的交互在三个级别上处理:缓存、卷和数据存储,每个级别都有其自己的 cookie 对象类型

COOKIE

C 类型

缓存 cookie

struct fscache_cache

卷 cookie

struct fscache_volume

数据存储 cookie

struct fscache_cookie

除了作为 API 函数的参考点外,Cookie 还用于向缓存提供一些文件系统数据、管理状态和在访问期间固定缓存。每个 cookie 都有一个调试 ID,该 ID 包含在跟踪点中,以便更容易关联跟踪。但请注意,调试 ID 只是从递增计数器分配的,最终会回绕。

缓存后端和网络文件系统都可以请求缓存 cookie - 如果它们请求相同名称的 cookie,它们将获得相同的 cookie。但是,卷和数据 cookie 仅应文件系统的要求创建。

缓存 Cookie

缓存在 API 中由缓存 cookie 表示。这些是类型为 的对象

struct fscache_cache {
        void            *cache_priv;
        unsigned int    debug_id;
        char            *name;
        ...
};

缓存后端可能对一些字段感兴趣。debug_id 可用于跟踪以匹配引用同一缓存的行,并且 name 是注册缓存时使用的名称。cache_priv 成员是缓存上线时由缓存提供的私有数据。其他字段供内部使用。

注册缓存

当缓存后端想要使缓存上线时,它应该首先注册缓存名称,这将为其获取缓存 cookie。这可以通过以下方式完成

struct fscache_cache *fscache_acquire_cache(const char *name);

这将查找并可能创建一个缓存 cookie。缓存 cookie 可能已被正在查找它的网络文件系统创建,在这种情况下,将使用该缓存 cookie。如果缓存 cookie 未被其他缓存使用,则会将其移动到准备状态,否则将返回 busy。

如果成功,缓存后端就可以开始设置缓存。如果初始化失败,缓存后端应调用

void fscache_relinquish_cache(struct fscache_cache *cache);

重置并丢弃 cookie。

使缓存上线

缓存设置完成后,可以通过调用以下命令使其上线

int fscache_add_cache(struct fscache_cache *cache,
                      const struct fscache_cache_ops *ops,
                      void *cache_priv);

这将缓存操作表指针和缓存私有数据存储到缓存 cookie 中,并将缓存移动到活动状态,从而允许进行访问。

从服务中撤销缓存

缓存后端可以通过调用此函数从服务中撤销缓存

void fscache_withdraw_cache(struct fscache_cache *cache);

这将缓存移动到撤销状态,以防止启动新的缓存和卷级访问,然后等待未完成的缓存级访问完成。

然后,缓存必须遍历其具有的数据存储对象,并告知 fscache 撤销它们,调用

void fscache_withdraw_cookie(struct fscache_cookie *cookie);

在每个对象所属的 cookie 上。这将计划撤销指定的 cookie。这将卸载到工作队列。缓存后端可以通过调用以下命令等待完成

void fscache_wait_for_objects(struct fscache_cache *cache);

撤销所有 cookie 后,缓存后端可以撤销所有卷,调用

void fscache_withdraw_volume(struct fscache_volume *volume);

告知 fscache 已撤销卷。这将等待卷上所有未完成的访问完成,然后返回。

当缓存完全撤销后,应通过调用以下命令通知 fscache

void fscache_relinquish_cache(struct fscache_cache *cache);

清除 cookie 中的字段并丢弃调用方对其的引用。

卷 Cookie

在缓存中,数据存储对象组织成逻辑卷。这些在 API 中表示为类型为 的对象

struct fscache_volume {
        struct fscache_cache            *cache;
        void                            *cache_priv;
        unsigned int                    debug_id;
        char                            *key;
        unsigned int                    key_hash;
        ...
        u8                              coherency_len;
        u8                              coherency[];
};

这里有许多缓存后端感兴趣的字段

  • cache - 父缓存 cookie。

  • cache_priv - 缓存用于隐藏私有数据的位置。

  • debug_id - 用于记录在跟踪点中的调试 ID。

  • key - 一个可打印的字符串,其中不包含“/”字符,它表示卷的索引键。该键以 NUL 结尾,并填充为 4 字节的倍数。

  • key_hash - 索引键的哈希值。这应该相同,无论 cpu 架构和字节序如何。

  • coherency - 当卷绑定到缓存中时应检查的一段一致性数据。

  • coherency_len - 一致性缓冲区中的数据量。

数据存储 Cookie

卷是数据存储对象的逻辑组,每个对象都通过 cookie 表示给网络文件系统。Cookie 在 API 中表示为类型为 的对象

struct fscache_cookie {
        struct fscache_volume           *volume;
        void                            *cache_priv;
        unsigned long                   flags;
        unsigned int                    debug_id;
        unsigned int                    inval_counter;
        loff_t                          object_size;
        u8                              advice;
        u32                             key_hash;
        u8                              key_len;
        u8                              aux_len;
        ...
};

cookie 中缓存后端感兴趣的字段是

  • volume - 父卷 cookie。

  • cache_priv - 缓存用于隐藏私有数据的位置。

  • flags - 一组位标志,包括

    • FSCACHE_COOKIE_NO_DATA_TO_READ - 缓存中没有可读取的数据,因为 cookie 已创建或失效。

    • FSCACHE_COOKIE_NEEDS_UPDATE - 一致性数据和/或对象大小已更改,需要提交。

    • FSCACHE_COOKIE_LOCAL_WRITE - netfs 的数据已在本地修改,因此缓存对象相对于服务器可能处于不一致状态。

    • FSCACHE_COOKIE_HAVE_DATA - 如果成功将数据存储到缓存中,则后端应设置此标志。

    • FSCACHE_COOKIE_RETIRED - 该 cookie 在被放弃时失效,应丢弃缓存的数据。

  • debug_id - 用于记录在跟踪点中的调试 ID。

  • inval_counter - 在 cookie 上完成的失效次数。

  • advice - 有关如何使用 cookie 的信息。

  • key_hash - 索引键的哈希值。这应该相同,无论 cpu 架构和字节序如何。

  • key_len - 索引键的长度。

  • aux_len - 一致性数据缓冲区的长度。

每个 cookie 都有一个索引键,该索引键可以内联存储到 cookie 或其他位置。可以通过调用以下命令获取指向此键的指针

void *fscache_get_key(struct fscache_cookie *cookie);

索引键是一个二进制 blob,其存储空间填充为 4 字节的倍数。

每个 cookie 还有一个用于一致性数据的缓冲区。这也可能是内联的或与 cookie 分离的,可以通过调用以下命令获得一个指针

void *fscache_get_aux(struct fscache_cookie *cookie);

缓存管理 API

缓存后端通过提供一个操作表来实现缓存管理 API,fscache 可以使用该表来管理缓存的各个方面。这些都保存在类型为 的结构中

struct fscache_cache_ops {
        const char *name;
        ...
};

这包含缓存后端驱动程序的可打印名称,以及指向方法的许多指针,以允许 fscache 请求管理缓存

  • 设置卷 cookie [可选]

    void (*acquire_volume)(struct fscache_volume *volume);
    

    当创建卷 cookie 时会调用此方法。调用方拥有缓存级访问锁,以防止缓存在此期间消失。此方法应设置资源以访问缓存中的卷,并且在完成之前不应返回。

    如果成功,它可以将 cache_priv 设置为其自己的数据。

  • 清理卷 cookie [可选]

    void (*free_volume)(struct fscache_volume *volume);
    

    如果设置了 cache_priv,则在释放卷 cookie 时会调用此方法。

  • 查找缓存中的 cookie [强制]

    bool (*lookup_cookie)(struct fscache_cookie *cookie);
    

    调用此方法以查找/创建访问 cookie 的数据存储所需的资源。它是从工作线程中调用的,其中缓存中具有卷级访问锁,以防止其被撤销。

    如果成功,则应返回 true,否则返回 false。如果返回 false,则将调用 withdraw_cookie 操作(请参见下文)。

    如果查找失败,但仍然可以创建对象(例如,它之前没有被缓存),则

    void fscache_cookie_lookup_negative(
            struct fscache_cookie *cookie);
    

    可以调用以允许网络文件系统继续并开始下载内容,同时缓存后端继续执行创建内容的工作。

    如果成功,则可以设置 cookie->cache_priv

  • 撤销对象而不持有任何 cookie 访问计数 [强制]

    void (*withdraw_cookie)(struct fscache_cookie *cookie);
    

    当 netfs 放弃 cookie、被缓存后端撤销或剔除,或者在 fscache 一段时间不使用后关闭 cookie 时,将调用此方法以从服务中撤销 cookie。

    调用方不持有任何访问锁,但它是从不可重入的工作项中调用的,以管理可能发生撤销的各种方式之间的竞争。

    如果关联的数据要从缓存中移除,cookie 将会被设置 FSCACHE_COOKIE_RETIRED 标志。

  • 更改数据存储对象的大小 [强制]

    void (*resize_cookie)(struct netfs_cache_resources *cres,
                          loff_t new_size);
    

    当由于本地截断导致 netfs 文件的大小发生更改时,会调用此方法来通知缓存后端。缓存后端应在返回之前进行所有必要的更改,因为此操作是在 netfs inode 互斥锁下完成的。

    调用者持有 cookie 级别的访问锁,以防止与撤回发生竞争,并且 netfs 必须将 cookie 标记为正在使用,以防止垃圾回收或剔除删除任何资源。

  • 使数据存储对象失效 [强制]

    bool (*invalidate_cookie)(struct fscache_cookie *cookie);
    

    当网络文件系统检测到第三方修改或在本地进行 O_DIRECT 写入时,会调用此方法。 这会请求缓存后端丢弃此对象在缓存中的所有数据,并重新开始。 如果成功,则应返回 true,否则返回 false。

    在入口处,新的 I/O 操作将被阻止。 一旦缓存准备好再次接受 I/O,后端应通过调用释放该阻塞

    void fscache_resume_after_invalidation(struct fscache_cookie *cookie);
    

    如果该方法返回 false,则将撤回此 cookie 的缓存。

  • 准备对缓存进行本地修改 [强制]

    void (*prepare_to_write)(struct fscache_cookie *cookie);
    

    当网络文件系统发现由于本地写入或截断而需要修改缓存内容时,会调用此方法。 这使缓存有机会注意到缓存对象可能与服务器不一致,并且可能需要在以后写回。 如果未正确提交,这也可能导致缓存的数据在以后重新绑定时被丢弃。

  • 为 netfs lib 开始操作 [强制]

    bool (*begin_operation)(struct netfs_cache_resources *cres,
                            enum fscache_want_state want_state);
    

    当正在设置 I/O 操作(读取、写入或调整大小)时,会调用此方法。 调用者持有 cookie 的访问锁,并且必须将 cookie 标记为正在使用。

    如果可以,后端应将其需要保留的任何资源附加到 netfs_cache_resources 对象并返回 true。

    如果无法完成设置,则应返回 false。

    want_state 参数指示调用者需要缓存对象处于的状态以及在操作期间要执行的操作

    • FSCACHE_WANT_PARAMS - 调用者只想访问缓存对象参数; 它尚不需要执行数据 I/O。

    • FSCACHE_WANT_READ - 调用者想要读取数据。

    • FSCACHE_WANT_WRITE - 调用者想要写入或调整缓存对象的大小。

    请注意,如果 cookie 仍在创建中,则 cookie 的 cache_priv 可能没有任何附加内容。

数据 I/O API

缓存后端通过 netfs 库的 struct netfs_cache_ops 提供数据 I/O API,该结构通过上述 begin_operation 方法附加到 struct netfs_cache_resources

有关描述,请参见 网络文件系统帮助程序库

杂项函数

FS-Cache 提供了一些缓存后端可能会使用的实用程序

  • 注意缓存中发生 I/O 错误

    void fscache_io_error(struct fscache_cache *cache);
    

    这告诉 FS-Cache 缓存中发生了 I/O 错误。 这将阻止在缓存上启动任何新的 I/O。

    这实际上不会撤回缓存。 必须单独完成。

  • 注意由于失败导致 cookie 停止缓存

    void fscache_caching_failed(struct fscache_cookie *cookie);
    

    这表示在 cookie 上执行的缓存由于某种原因而失败,例如后备存储无法创建或失效失败,并且在该缓存重置之前,不应再在其上进行任何 I/O 操作。

  • 计算 I/O 请求

    void fscache_count_read(void);
    void fscache_count_write(void);
    

    这些记录从缓存读取/写入的数据。 这些数字显示在 /proc/fs/fscache/stats 中。

  • 计算空间不足错误

    void fscache_count_no_write_space(void);
    void fscache_count_no_create_space(void);
    

    这些记录缓存中的 ENOSPC 错误,分为数据写入失败和文件系统对象创建失败(例如 mkdir)。

  • 计算剔除的对象

    void fscache_count_culled(void);
    

    这记录了对象的剔除。

  • 从一组缓存资源获取 cookie

    struct fscache_cookie *fscache_cres_cookie(struct netfs_cache_resources *cres)
    

    从缓存资源中提取指向 cookie 的指针。 如果未设置任何 cookie,则可能返回 NULL cookie。

API 函数参考

读取 cookie 的状态

参数

struct fscache_cookie *cookie

要查询的 cookie

描述

获取 cookie 的状态,在 cookie 内容和状态值之间施加顺序。 与 fscache_set_cookie_state() 配对使用。

void *fscache_get_key(struct fscache_cookie *cookie)

获取指向 cookie 密钥的指针

参数

struct fscache_cookie *cookie

要查询的 cookie

描述

返回指向存储 cookie 密钥的位置的指针。

void fscache_count_object(struct fscache_cache *cache)

告知 fscache 已添加对象

参数

struct fscache_cache *cache

要计入的缓存

描述

告知 fscache 已向缓存添加了对象。 这将阻止缓存拆除缓存结构,直到对象被取消计数。

void fscache_uncount_object(struct fscache_cache *cache)

告知 fscache 对象已删除

参数

struct fscache_cache *cache

要计入的缓存

描述

告知 fscache 已从缓存中删除对象,并且将不再被访问。 在此之后,可以销毁缓存 cookie。

void fscache_wait_for_objects(struct fscache_cache *cache)

等待所有对象被撤回

参数

struct fscache_cache *cache

要查询的缓存

描述

等待缓存中的所有现有对象完成撤回并消失。