缓存后端 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

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

缓存后端和网络文件系统都可以请求缓存 cookie - 如果它们请求具有相同名称的 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 未被另一个缓存使用,它将被移动到准备状态,否则它将返回繁忙。

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

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

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

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 op(参见下文)。

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

    void fscache_cookie_lookup_negative(
            struct fscache_cookie *cookie);
    

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

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

  • 撤回没有任何 cookie 访问计数的对象 [强制]

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

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

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

    如果应从缓存中删除关联的数据,则 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(通过上面描述的 begin_operation 方法附加到 struct netfs_cache_resources)提供数据 I/O API。

有关说明,请参见网络文件系统服务库

其他函数

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

要查询的缓存

说明

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