GVKun编程网logo

移植facebook flashcache模块支持 linux kernel 4.13以上(facebook install download)

27

在这篇文章中,我们将带领您了解移植facebookflashcache模块支持linuxkernel4.13以上的全貌,包括facebookinstalldownload的相关情况。同时,我们还将为您

在这篇文章中,我们将带领您了解移植facebook flashcache模块支持 linux kernel 4.13以上的全貌,包括facebook install download的相关情况。同时,我们还将为您介绍有关Apache Cassandra 在 Facebook 的应用、cephfs linux kernel client 针对 fscache 的操作、cephfs linux kernel client 针对 linux page cache 的操作、cephfs linux kernel client针对fscache的操作的知识,以帮助您更好地理解这个主题。

本文目录一览:

移植facebook flashcache模块支持 linux kernel 4.13以上(facebook install download)

移植facebook flashcache模块支持 linux kernel 4.13以上(facebook install download)

环境

准备在ubuntu 18.04 lts下搭建kvm+libvirt+glusterfs的虚拟化环境。

4台服务器是2块SSD,4块SATA(5400RPM)。

尝试了gluster tier,效果不好。

对于虚拟化环境下大文件的存储,tier的promote和demote的策略很难设置,

在大文件发生大量数据交换时会出现tier层"no space left"的错误,文件无法写入。

在没有更好的解决方案之前,facebook的flashcache(https://github.com/facebookarchive/flashcache )对于提速SATA盘的作用还是非常显著的。

但ubuntu18.04的apt源还没有。

https://launchpad.net/flashcache/+packages

错误

于是下载flashcache源码编译dkms模块的时候,报错:

DKMS make.log for flashcache-3.1.3+git20150701 for kernel 4.15.0-36-generic (x86_64)
Fri Oct 12 15:06:00 UTC 2018
make -C /lib/modules/4.15.0-36-generic/build M=/var/lib/dkms/flashcache/3.1.3+git20150701/build modules V=0
make[1]: Entering directory ''/usr/src/linux-headers-4.15.0-36-generic''
Makefile:975: "Cannot use CONFIG_STACK_VALIDATION=y, please install libelf-dev, libelf-devel or elfutils-libelf-devel"
  CC [M]  /var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_conf.o
  CC [M]  /var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_main.o
  CC [M]  /var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_subr.o
/var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_subr.c: In function ‘flashcache_bio_endio’:
/var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_subr.c:742:7: error: ‘struct bio’ has no member named ‘bi_error’; did you mean ‘bi_iter’?
  bio->bi_error = error;
       ^~~~~~~~
       bi_iter
scripts/Makefile.build:332: recipe for target ''/var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_subr.o'' failed
make[2]: *** [/var/lib/dkms/flashcache/3.1.3+git20150701/build/flashcache_subr.o] Error 1
Makefile:1551: recipe for target ''_module_/var/lib/dkms/flashcache/3.1.3+git20150701/build'' failed
make[1]: *** [_module_/var/lib/dkms/flashcache/3.1.3+git20150701/build] Error 2
make[1]: Leaving directory ''/usr/src/linux-headers-4.15.0-36-generic''
Makefile:35: recipe for target ''modules'' failed
make: *** [modules] Error 2

OS内核的版本是4.15.0-36。

原因

根据错误提示:bio->bierror ‘struct bio’ has no member named ‘bierror’;

找了4.15的内核源码看看bio的struct的定义,

bio是在include/linux/blktypes.h中定义。

https://elixir.bootlin.com/linux/v4.15/source/include/linux/blktypes.h

struct bio {
    struct bio      *bi_next;   /* request queue link */
    struct gendisk      *bi_disk;
    unsigned int        bi_opf;     /* bottom bits req flags,
                         * top bits REQ_OP. Use
                         * accessors.
                         */
    unsigned short      bi_flags;   /* status, etc and bvec pool number */
    unsigned short      bi_ioprio;
    unsigned short      bi_write_hint;
    blk_status_t        bi_status;
    u8          bi_partno;

    /* Number of segments in this BIO after
     * physical address coalescing is performed.
     */
    unsigned int        bi_phys_segments;

    /*
     * To keep track of the max segment size, we account for the
     * sizes of the first and last mergeable segments in this bio.
     */
    unsigned int        bi_seg_front_size;
    unsigned int        bi_seg_back_size;

    struct bvec_iter    bi_iter;

    atomic_t        __bi_remaining;
    bio_end_io_t        *bi_end_io;

    void            *bi_private;
#ifdef CONFIG_BLK_CGROUP
    /*
     * Optional ioc and css associated with this bio.  Put on bio
     * release.  Read comment on top of bio_associate_current().
     */
    struct io_context   *bi_ioc;
    struct cgroup_subsys_state *bi_css;
#ifdef CONFIG_BLK_DEV_THROTTLING_LOW
    void            *bi_cg_private;
    struct blk_issue_stat   bi_issue_stat;
#endif
#endif
    union {
#if defined(CONFIG_BLK_DEV_INTEGRITY)
        struct bio_integrity_payload *bi_integrity; /* data integrity */
#endif
    };

    unsigned short      bi_vcnt;    /* how many bio_vec''s */

    /*
     * Everything starting with bi_max_vecs will be preserved by bio_reset()
     */

    unsigned short      bi_max_vecs;    /* max bvl_vecs we can hold */

    atomic_t        __bi_cnt;   /* pin count */

    struct bio_vec      *bi_io_vec; /* the actual vec list */

    struct bio_set      *bi_pool;

    /*
     * We can inline a number of vecs at the end of the bio, to avoid
     * double allocations for a small number of bio_vecs. This member
     * MUST obviously be kept at the very end of the bio.
     */
    struct bio_vec      bi_inline_vecs[0];
};

里面根本没有bierror。 再翻翻以前版本的代码,在4.12的bio定义里发现了bierror: https://elixir.bootlin.com/linux/v4.12.14/source/include/linux/blk_types.h

应该是从4.13版本内核之后,bio的结构定义发生了变化。

struct bio {
    struct bio      *bi_next;   /* request queue link */
    struct block_device *bi_bdev;
    int         bi_error;
    unsigned int        bi_opf;     /* bottom bits req flags,
                         * top bits REQ_OP. Use
                         * accessors.
                         */
    unsigned short      bi_flags;   /* status, etc and bvec pool number */
    unsigned short      bi_ioprio;

解决

修改flashcache_subr.c,将 bi_error改成bi_status

重新编译,ok。

 

更新:

flashcache_subr.c按如下修改,可以兼容以前版本的内核。

void
flashcache_bio_endio(struct bio *bio, int error,
                     struct cache_c *dmc, struct timeval *start_time)
{
        if (unlikely(dmc->sysctl_io_latency_hist &&
                     start_time != NULL &&
                     start_time->tv_sec != 0))
                flashcache_record_latency(dmc, start_time);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
        bio_endio(bio, bio->bi_size, error);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0)
        bio_endio(bio, error);
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4,13,0)
        bio->bi_error = error;
        bio_endio(bio);
#else
        bio->bi_status = error;

        bio_endio(bio);
#endif
}
 

 

Apache Cassandra 在 Facebook 的应用

Apache Cassandra 在 Facebook 的应用

谁说 Facebook 弃用 Cassandra?相反 Facebook 拥有全世界最大的单个 Cassandra 集群部署,而且他们对 Cassandra 做了很多性能优化,包括 Cassandra on RocksDB 以提升 Cassandra 的响应时间。

在 Instagram (Instagram是Facebook公司旗下一款免费提供在线图片及视频分享的社交应用软件,于2010年10月发布。)上,我们拥有世界上最大的 Apache Cassandra 数据库部署。我们在 2012 年开始使用 Cassandra 取代 Redis ,在生产环境中支撑欺诈检测,Feed 和 Direct inbox 等产品。起初我们在 AWS 环境中运行了 Cassandra 集群,但是当 Instagram 架构发生变化时,我们将 Cassandra 集群迁移到Facebook 的基础架构中。我们对 Cassandra 的可靠性和可用性有了非常好的体验,但是在读取数据延迟方面我们觉得他需要改进。

去年 Instagram 的 Cassandra 团队开始着手这个项目,以显着减少 Cassandra 的读取延迟,我们称之为 Rocksandra。 在这篇文章中,我将描述该项目的动机,我们克服的挑战以及内部和公共云环境中的性能指标。

动机

在 Instagram 上,我们大量使用 Apache Cassandra 作为通用键值存储服务。Instagram 的大多数 Cassandra 请求都是在线的,因此为了向数亿 Instagram 用户提供可靠且响应迅速的用户体验,我们有很高的 SLA 要求。

Instagram 可靠性 SLA 保持为5-9s,这意味着在任何给定时间,请求失败率应小于0.001%。为了提高性能,我们主动监控不同 Cassandra 集群的吞吐量和延迟,尤其是 P99 读取延迟。

下面的图显示了一个生产 Cassandra 集群的客户端延迟。蓝线是平均读取延迟(5ms),橙色线是 P99 读取延迟(在25ms到60ms的范围内)。

经过调查,我们发现 JVM 垃圾收集器(GC)对延迟峰值做出了很大贡献。我们定义了一个称为 GC 停滞百分比的度量,用于衡量Cassandra 服务器执行 GC(Young Gen GC)并且无法响应客户端请求的时间百分比。结果显示我们生产 Cassandra 服务器上的 GC 停滞百分比。在最低请求流量时间窗口期间为1.25%,在高峰时段可能高达2.5%。

这表明 Cassandra 服务器实例在垃圾收集上花费 2.5% 的运行时间,而这段时间是不能服务客户端请求的。GC 开销显然对我们的 P99 延迟有很大影响,因此如果我们可以降低 GC 停顿百分比,我们将能够显着降低P99延迟。

解决办法

Apache Cassandra 是一个分布式数据库,并用 Java 编写了基于 LSM 树的存储引擎。 我们发现存储引擎中的组件,如memtable,压缩,读/写路径等,在 Java 堆中创建了很多对象,并为 JVM 产生了大量开销。为了减少来自存储引擎的GC影响,我们考虑了不同的方法,并最终决定开发C++存储引擎来替换现有的引擎。

我们不想从头开始构建新的存储引擎,因此我们决定在 RocksDB 之上构建新的存储引擎。

RocksDB 是一个开源的,高性能嵌入式键值数据库。它是用 C++ 编写的,并为 C++,C 和 Java 提供官方 API。RocksDB 针对性能进行了优化,尤其是在 SSD 等快速存储方面。它在业界广泛用作 MySQL,mongoDB 和其他流行数据库的存储引擎。

挑战

在 RocksDB 上实现新的存储引擎时,我们克服了三个主要挑战:

第一个挑战是 Cassandra 还没有可插拔的存储引擎架构,这意味着现有的存储引擎与数据库中的其他组件耦合在一起。为了在大规模重构和快速迭代之间找到平衡点,我们定义了一个新的存储引擎 API,包括最常见的读/写和流接口。这样我们就可以在 API 后面实现新的存储引擎,并将其注入 Cassandra 内部的相关代码路径。

其次,Cassandra 支持丰富的数据类型和表模式,而 RocksDB 提供纯粹的键值接口。我们仔细定义了编码/解码算法,使得我们使用 RocksDB 数据结构来构建 Cassandra 数据模型,并支持与原始 Cassandra 相同的查询语义。

第三个挑战是关于 streaming。 Streaming 在 Cassandra 这样的分布式数据库是很重要组件。每当我们从 Cassandra 集群加入或删除节点时,Cassandra 都需要在不同节点之间传输数据以平衡集群中的负载。现有的 streaming 实现基于当前存储引擎的。因此,我们必须将它们彼此分离,创建一个抽象层,并使用 RocksDB API 重新实现 streaming 传输。对于高 streaming 吞吐量,我们现在首先将数据流式传输到临时 sst 文件,然后使用 RocksDB 提取文件 API 立即将它们批量加载到 RocksDB 实例中。

性能指标

经过大约一年的开发和测试,我们已经完成了第一个版本的实现,并成功将其推广到 Instagram 中的几个生产 Cassandra 集群。在我们的一个生产集群中,P99读取延迟从60ms降至20ms。 我们还观察到该集群上的GC停滞从2.5%下降到0.3%,这减少了10倍!

我们还想验证 Rocksandra 在公共云环境中是否表现良好。我们在 AWS 环境中使用三个 i3.8 xlarge EC2 实例部署了一个 Cassandra 集群,每个实例具有 32 个核,244GB内存和 带有4个nvme闪存盘的raid0。

我们使用 NDBench 作为基准测试,并使用这个框架中的默认表模式:

TABLE emp (
 emp_uname text PRIMARY KEY,
emp_dept text,
emp_first text,
emp_last text
 )

我们将 250M 6KB 行数据预先加载到数据库中(每个服务器在磁盘上存储大约500GB的数据)。我们在 NDBench 中配置了128个读客户端和128个写客户端。

我们测试了不同的工作负载并测量了 avg/P99/P999 读/写延迟。如我们所见,Rocksandra 提供了更低且一致的读/写延迟。

我们还测试了一个只读工作负载并观察到,在类似的P99读取延迟(2ms)下,Rocksandra 读取吞吐量提高了10倍(Rocksandra为300K/s,C * 3.0为 30K/s)。


未来工作

我们开源了 Rocksandra 代码库和基准框架,您可以从Github下载(https://github.com/Instagram/cassandra/tree/rocks_3.0),在您自己的环境中试用!

下一步,我们正在积极开发更多 C 功能,如二级索引,修复等。我们还在开发一个 C 可插拔存储引擎架构,以便将我们的工作贡献给Apache Cassandra 社区。

本文翻译自:https://instagram-engineering.com/open-sourcing-a-10x-reduction-in-apache-cassandra-tail-latency-d64f86b43589

原文链接​

本文为云栖社区原创内容,未经允许不得转载。

cephfs linux kernel client 针对 fscache 的操作

cephfs linux kernel client 针对 fscache 的操作

针对 inode 在 fscache 中操作主要集中在数据结构 struct fscache_cookie_def 中,具体的数据结构及其操作如下:

static const struct fscache_cookie_def ceph_fscache_inode_object_def = {

        .name           = "CEPH.inode",

        .type           = FSCACHE_COOKIE_TYPE_DATAFILE,

        .get_key        = ceph_fscache_inode_get_key,

        .get_attr       = ceph_fscache_inode_get_attr,

        .get_aux        = ceph_fscache_inode_get_aux,

        .check_aux      = ceph_fscache_inode_check_aux,

        .now_uncached   = ceph_fscache_inode_now_uncached,

};

 

ceph_fscache_inode_get_key (void *cookie_netfs_data, void *buffer, uint16_t maxbuf)    读取 struct ceph_inode_info 中的 i_vino 信息到 buffer

|__从参数 cookie_netfs_data 的到 struct ceph_inode_info 数据结构

|__调用 memcpy () 将 struct ceph_inode_info 中的 i_vino 内容复制到 buffer 中

 

ceph_fscache_inode_get_attr (void *cookie_netfs_data, uint64_t *size)    读取 struct ceph_inode_info 中 vfs_inode 的大小

|__从参数 cookie_netfs_data 的到 struct ceph_inode_info 数据结构

|__调用 i_size_read () 函数读取 struct ceph_inode_info 中 vfs_inode 的大小且保存到 size 中

 

ceph_fscache_inode_get_aux(void *cookie_netfs_data, void *buffer, uint16_t bufmax)

|__从参数 cookie_netfs_data 的到 struct ceph_inode_info 数据结构

|__初始化 struct ceph_aux_inode 信息

|__从 struct ceph_inode_info 结构中初始化 struct ceph_aux_inode 信息

|__将 struct ceph_aux_inode 信息复制到 buffer 中

 

ceph_fscache_inode_check_aux(void *cookie_netfs_data, void *data, uint16_t dlen)

|__从参数 cookie_netfs_data 的到 struct ceph_inode_info 数据结构

|__从 struct ceph_inode_info 结构中初始化 struct ceph_aux_inode 信息

|__比较参数中的 data 和初始化后的 struct ceph_aux_inode 信息

 

ceph_fscache_inode_now_uncached(void *cookie_netfs_data)

|__从参数 cookie_netfs_data 的到 struct ceph_inode_info 数据结构

|__调用 pagevec_init () 函数初始化 pvec

|__调用 pagevec_lookup () 函数查找 struct ceph_inode_info 里 vfs_inode.i_mapping 里所有映射的物理内存页

|__调用 ClearPageFsCache () 函数清除物理内存页的 fscache

|__调用 pagevec_release () 函数释放 pvec

 

ceph_fscache_register_inode_cookie(struct inode *inode)

|__从参数 inode 中得到 struct ceph_inode_info 以及 struct ceph_fs_client 信息

|__调用 fscache_acquire_cookie () 函数得到访问 ceph fscache 的 cookie 值且将该 cookie 值保存到 struct ceph_inode_info 的 fscache 中

 

ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci)

|__调用 fscache_uncache_all_inode_pages () 函数从 cache 中删除所有 inode 占用的物理内存页

|__调用 fscache_relinquish_cookie () 函数删除 cookie

 

ceph_fscache_can_enable(void *data)

|__从参数 data 中得到 struct inode 数据结构

|__调用 inode_is_open_for_write (inode) 函数且返回该函数返回值的非

 

ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)

|__从参数 inode 得到 struct ceph_inode_info 数据结构

|__调用 fscache_cookie_valid () 函数检查 struct ceph_inode_info 中的 fscache 是否有效,若无效则直接返回

|__调用 inode_is_open_for_write () 函数检查 inode 是打开并可写

    |__调用 fscache_disable_cookie () 函数禁用 cookie

    |__调用 fscache_uncache_all_inode_pages () 函数删除掉 cache 中 inode 的所有物理内存页

|__调用 inode_is_open_for_write () 函数检查 inode 是未打开且不可写

    |__调用 fscache_enable_cookie () 函数启用 cookie

 

ceph_fscache_register()

|__调用 fscache_register_netfs () 函数注册 ceph 的 fscache

 

ceph_fscache_unregister()

|__调用 fscache_unregister_netfs () 函数注销 ceph 的 fscache

 

ceph_fscache_register_fs(struct ceph_fs_client *fs)

|__调用 fscache_acquire_cookie () 函数得到访问 ceph fscache 的 cookie 值且将该 cookie 值保存到 struct ceph_fs_client 的 fscache 中

 

ceph_fscache_unregister_fs(struct ceph_fs_client *fsc)

|__调用 fscache_relinquish_cookie () 函数释放 fsc->fscache 数据结构

 

ceph_fscache_session_get_key(void *cookie_netfs_data, void *buffer, uint16_t maxbuf)

|__从参数 cookie_netfs_data 的到 struct ceph_fs_client 数据结构

|__调用 memcpy () 函数将 struct ceph_fs_client 数据结构中的 client->fsid 值复制到 buffer 中

 

ceph_readpage_from_fscache(struct inode *inode, struct page *page)

|__从参数 inode 得到 struct ceph_inode_info 数据结构

|__调用 fscache_read_or_alloc_page () 函数从 fscache 中读取 inode 的内容并写到 page 中

 

ceph_readpages_from_fscache(struct inode *inode, struct address_space *mapping, struct list_head *pages, unsigned *nr_pages)

|__从参数 inode 得到 struct ceph_inode_info 数据结构

|__调用 fscache_read_or_alloc_pages () 函数从 fscahe 中读取 mapping 中的数据并写入到 pages 中

 

ceph_readpage_to_fscache(struct inode *inode, struct page *page)

|__从参数 inode 得到 struct ceph_inode_info 数据结构

|__调用 fscache_write_page () 函数将物理内存页 page 中的数据同步到 fscache 中

 

ceph_invalidate_fscache_page(struct inode *inode, struct page *page)

|__从参数 inode 得到 struct ceph_inode_info 数据结构

|__调用 fscache_wait_on_page_write () 函数等待 page 写入完成

|__调用 fscache_uncache_page () 函数将 page 中的内容从 struct ceph_inode_info 中的 fscache 中删除

 

ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)

|__调用 cache_valid () 函数检查 ci 指定的 fscache 是否有效,若无效

    |__调用 fscache_check_consistency () 函数校验 ci->fscache 的一致性,若不一致

        |__调用 fscache_invalidate () 函数设置 ci->fscache 无效

    |__设置 ci->i_fscache_gen=ci->i_rdcache_gen

 

cephfs linux kernel client 针对 linux page cache 的操作

cephfs linux kernel client 针对 linux page cache 的操作

针对 linux page cache 的操作主要体现在 struct address_space_operations 数据结构中,cephfs 处理 linux page cache 的函数集合如下:

const struct address_space_operations ceph_aops = {

        .readpage = ceph_readpage,

        .readpages = ceph_readpages,

        .writepage = ceph_writepage,

        .writepages = ceph_writepages_start,

        .write_begin = ceph_write_begin,

        .write_end = ceph_write_end,

        .set_page_dirty = ceph_set_page_dirty,

        .invalidatepage = ceph_invalidatepage,

        .releasepage = ceph_releasepage,

        .direct_IO = ceph_direct_io,

};

 

ceph_readpage(struct file *filp, struct page *page)

|__调用 readpage_nounlock (filep, page)     在加锁的情况下读取一个物理内存页的数据

    |__确定 page 的 offset 没有超出 inode 的总长度

    |__调用 ceph_readpage_from_fscache () 函数尝试从 fscache 中读取一个物理内存页的数据

        |__若读取成功则直接返回

    |__调用 ceph_osdc_readpages () 函数从 ceph 集群中读取一个物理内存页的数据

        |__调用 ceph_osdc_new_reqeust () 函数创建一个读请求

        |__调用 osd_req_op_extent_osd_data_pages () 函数为读请求的返回内容分配内存空间

        |__调用 ceph_osdc_start_request () 函数将读请求同步发送给 ceph 集群

    |__调用 flush_dcache_page () 函数刷 page 到 dcache 中

    |__调用 SetPageUptodate () 函数设置物理内存页的状态是 update 的

    |__调用 ceph_readpage_to_fscache () 函数将新读到的物理内存页更新到 fscache 中

|__调用 unlock_page (page)

    |__调用 clear_bit_unlock () 函数为 page 解锁

    |__调用 wake_up_page () 函数唤醒等待该 page 的相关进程

 

ceph_readpages (struct file *file, struct address_space *mapping, struct list_head *page_list, unsigned nr_pages)    读取多个页

|__调用 ceph_readpages_from_fscache () 函数尝试从 fscache 中读取多个物理内存页的数据

    |__若读取成功则直接返回

|__遍历 page_list

    |__调用 start_read () 函数读取数据到 page_list 所包含的物理内存页

        |__调用 ceph_osdc_new_reqeust () 函数创建一个读请求

        |__调用 calc_pages_for (0, len) 函数得到读取指定长度 len 的数据需要的物理内存页数

        |__从 page_list 中摘下指定数量的物理内存页

        |__调用 osd_req_op_extent_osd_data_pages () 函数将从 page_list 中摘下的物理内存页作为读请求的接收缓冲

        |__设置读请求完成后的回调函数为 finish_read ()

        |__调用 ceph_osdc_start_request () 函数将读请求同步发送给 ceph 集群

 

finish_read (struct ceph_osd_request *req)        从 ceph 集群中读操作结束后的回调函数

|__遍历读取到的所有物理内存页

    |__调用 flush_dcache_page () 函数将 page 中的内存刷到 dcache 中

    |__调用 SetPageUptodate () 函数设置 page 的状态是 uptodate 的

    |__调用 ceph_readpage_to_fscache () 函数将读取到的 page 内存同步到 fscache 中

 

ceph_writepage(struct page *page, struct writeback_control *wbc)

|__调用 writepage_nounlock (page,wbc) 函数同步 page 信息到 ceph 集群

    |__调用 page_snap_context () 函数得到 page 的 snap context 信息 (page 将 CephSnapContext 信息写入到 page 的 private 中)

    |__调用 set_page_writeback (page) 函数设置 page writeback 标识

    |__调用 ceph_osdc_writepages () 函数将 page 信息同步写到 ceph 集群

        |__调用 ceph_osdc_new_reqeust () 函数创建一个写请求

        |__调用 osd_req_op_extent_osd_data_pages () 函数为写请求设置写内容物理内存页

        |__调用 ceph_osdc_start_request () 函数将写请求同步发送给 ceph 集群

    |__设置 page->private=0,即:删除 page 的 CephSnapContext 信息

    |__调用 ClearPagePrivate (page) 函数清空 page 的 private

    |__调用 end_page_writeback () 函数

        |__调用 wake_up_page (page, PG_writeback) 函数唤醒在 page 上等待 writeback 完成的进程

 

ceph_writepages_start(struct address_space *mapping, struct writeback_control *wbc)

|__调用 pagevec_init (&pvec, 0) 函数初始化 struct pagevec 实例 pvec

|__从 wbc 的 range_start 和 range_end 中得到 start 和 end

|__调用 pagevec_lookup_tag (&pvec, mapping, PAGECACHE_TAG_DIRTY…) 函数从 mapping 中 radix tree 中找到 tags==PAGECACHE_TAG_DIRTY 的所有 pages 且将所有 pages 写入到 pvec 中

|__遍历所有 PAGECACHE_TAG_DIRTY 的 pages

    |__调用 page_offset () 函数得到 page 所在的 offset 值

    |__调用 ceph_calc_file_object_mapping () 函数得到从 offset 开始,长度是 len 的文件所占用的 objects 个数以及在 object 中的偏移

    |__将 page 添加到 pages 数组中

|__从 pages 数组中得到 offset 值,即:offset=page_offset (pages [0])

|__调用 ceph_osdc_new_request () 函数创建一个写数据请求

|__设置写数据请求的回调函数为 writepages_finish

|__调用 osd_req_op_extent_osd_data_pages () 函数添加写请求额外的数据

|__调用 ceph_osdc_start_request () 函数将写请求同步发送到 ceph 集群

 

writepages_finish(struct ceph_osd_request *req)

|__清除所有在发送写请求过程中产生的内存

 

ceph_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigend flags, staruct page **pagep, void **fsdata)

|__得到 pos 所在的 page 位置,即:index=pos >> PAGE_SHIFT

|__调用 grab_cache_page_write_begin (mapping, index, flags) 函数在 pagecache 中指定位置 index 出获取或创建一个物理内存页 page

    |__调用 pagecache_get_page () 函数在 pagecache 中指定位置 index 出获取或创建一个物理内存页 page

    |__调用 wait_for_stable_page (page) 函数等待该 page 上的 writeback 函数返回

|__调用 ceph_update_writeable_page (file, pos, len, page) 函数只允许往 clean page 里写入数据或者已经 dirty 的 snap context 里写入数据

    |__调用 wait_on_page_writeback (page) 函数等待 page 的 writeback 完成

    |__调用 page_snap_context (page) 函数得到该 page 的 snap context

    |__若 snap context 的 seq > oldest->seq

        |__调用 ceph_queue_writeback (inode) 函数将 inode 放入到 writeback 队列中

    |__调用 clear_page_dirty_for_io (page) 函数清除 page 上的 dirty 标识

    |__调用 writepage_nounlock (page, NULL) 函数将 page 数据同步的写入到 ceph 集群

    |__调用 PageUptodate (page) 检查 page 是否是 uptodate 的

        |__是则直接返回

    |__若 page 已经满了

        |__直接返回

    |__调用 i_size_read (inode) 函数得到 inode 的读数据的大小

    |__调用 readpage_nounlock (file, page) 函数从 ceph 集群中读取数据到 page 中

 

ceph_write_end(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page **page, void *fsdata)

|__若 copied < len

    |__调用 zero_user_segment (page, from+copied, len) 函数将 page 中从 from+copied 一直到 from+copied+len 的内存空间置 0

|__若 pos+copied > i_size_read (inode)

    |__调用 ceph_inode_set_size () 函数设置 inode 的 size 为 pos+copied

|__若 Page 不是 uptodate 的

    |__调用 SetPageUptodate (page) 函数设置 page 是 uptodate 的

|__调用 set_page_dirty (page) 函数设置 page 是 dirty 的

 

ceph_set_page_dirty(struct page *page)

|__若 PageDirty (page)

    |__直接返回

|__通过 mapping 的到 struct ceph_inode_info 结构

|__调用__ceph_have_pending_cap_snap () 函数检查 cephfs 是否有 snaps

    |__从 struct ceph_inode_info 结构中的 i_cap_snaps 列表中得到 struct ceph_cap_snap 结构

    |__从 struct ceph_cap_snap 结构中得到 struct ceph_snap_context 结构

|__若 cephfs 没有 snaps

    |__调用 ceph_get_snap_context () 函数从 struct ceph_inode_info 的 i_head_spapc 中得到 struct ceph_snap_context 结构

|__将 struct ceph_snap_context 结构设置到 page 的 private 中,即:page->private=snapc

|__调用__set_page_dirty_nobuffers () 函数将 page 在 address_spaces 中的 radix tree 中设置成 dirty

 

ceph_invalidatepage(struct page *page, unsigned int offset, unsigned int length)

|__调用 ceph_invalidate_fscache_page () 函数使得 page 在 fscache 中无效

|__若 page 没有 private

    |__直接返回

|__设置 page->private=0 清除 page 的 snaps

|__调用 ClearPagePriavte (page)

 

ceph_releasepage(struct page *page, gfp_t g)

|__调用 ceph_release_fscache_page () 函数在 fscache 中删除 page

|__返回!PagePrivate (page)

 

ceph_direct_io(struct kiocb *iocb, struct iov_iter *iter)

|__返回 - EINVAL

cephfs linux kernel client针对fscache的操作

cephfs linux kernel client针对fscache的操作

针对inode在fscache中操作主要集中在数据结构struct fscache_cookie_def中,具体的数据结构及其操作如下:

static const struct fscache_cookie_def ceph_fscache_inode_object_def = {

        .name           = "CEPH.inode",

        .type           = FSCACHE_COOKIE_TYPE_DATAFILE,

        .get_key        = ceph_fscache_inode_get_key,

        .get_attr       = ceph_fscache_inode_get_attr,

        .get_aux        = ceph_fscache_inode_get_aux,

        .check_aux      = ceph_fscache_inode_check_aux,

        .now_uncached   = ceph_fscache_inode_now_uncached,

};

 

ceph_fscache_inode_get_key(void *cookie_netfs_data, void *buffer, uint16_t maxbuf)    读取struct ceph_inode_info中的i_vino信息到buffer

|__从参数cookie_netfs_data的到struct ceph_inode_info数据结构

|__调用memcpy()将struct ceph_inode_info中的i_vino内容复制到buffer中

 

ceph_fscache_inode_get_attr(void *cookie_netfs_data, uint64_t *size)    读取struct ceph_inode_info中vfs_inode的大小

|__从参数cookie_netfs_data的到struct ceph_inode_info数据结构

|__调用i_size_read()函数读取struct ceph_inode_info中vfs_inode的大小且保存到size中

 

ceph_fscache_inode_get_aux(void *cookie_netfs_data, void *buffer, uint16_t bufmax)

|__从参数cookie_netfs_data的到struct ceph_inode_info数据结构

|__初始化struct ceph_aux_inode信息

|__从struct ceph_inode_info结构中初始化struct ceph_aux_inode信息

|__将struct ceph_aux_inode信息复制到buffer中

 

ceph_fscache_inode_check_aux(void *cookie_netfs_data, void *data, uint16_t dlen)

|__从参数cookie_netfs_data的到struct ceph_inode_info数据结构

|__从struct ceph_inode_info结构中初始化struct ceph_aux_inode信息

|__比较参数中的data和初始化后的struct ceph_aux_inode信息

 

ceph_fscache_inode_now_uncached(void *cookie_netfs_data)

|__从参数cookie_netfs_data的到struct ceph_inode_info数据结构

|__调用pagevec_init()函数初始化pvec

|__调用pagevec_lookup()函数查找struct ceph_inode_info里vfs_inode.i_mapping里所有映射的物理内存页

|__调用ClearPageFsCache()函数清除物理内存页的fscache

|__调用pagevec_release()函数释放pvec

 

ceph_fscache_register_inode_cookie(struct inode *inode)

|__从参数inode中得到struct ceph_inode_info以及struct ceph_fs_client信息

|__调用fscache_acquire_cookie()函数得到访问ceph fscache的cookie值且将该cookie值保存到struct ceph_inode_info的fscache中

 

ceph_fscache_unregister_inode_cookie(struct ceph_inode_info *ci)

|__调用fscache_uncache_all_inode_pages()函数从cache中删除所有inode占用的物理内存页

|__调用fscache_relinquish_cookie()函数删除cookie

 

ceph_fscache_can_enable(void *data)

|__从参数data中得到struct inode数据结构

|__调用inode_is_open_for_write(inode)函数且返回该函数返回值的非

 

ceph_fscache_file_set_cookie(struct inode *inode, struct file *filp)

|__从参数inode得到struct ceph_inode_info数据结构

|__调用fscache_cookie_valid()函数检查struct ceph_inode_info中的fscache是否有效,若无效则直接返回

|__调用inode_is_open_for_write()函数检查inode是打开并可写

    |__调用fscache_disable_cookie()函数禁用cookie

    |__调用fscache_uncache_all_inode_pages()函数删除掉cache中inode的所有物理内存页

|__调用inode_is_open_for_write()函数检查inode是未打开且不可写

    |__调用fscache_enable_cookie()函数启用cookie

 

ceph_fscache_register()

|__调用fscache_register_netfs()函数注册ceph的fscache

 

ceph_fscache_unregister()

|__调用fscache_unregister_netfs()函数注销ceph的fscache

 

ceph_fscache_register_fs(struct ceph_fs_client *fs)

|__调用fscache_acquire_cookie()函数得到访问ceph fscache的cookie值且将该cookie值保存到struct ceph_fs_client的fscache中

 

ceph_fscache_unregister_fs(struct ceph_fs_client *fsc)

|__调用fscache_relinquish_cookie()函数释放fsc->fscache数据结构

 

ceph_fscache_session_get_key(void *cookie_netfs_data, void *buffer, uint16_t maxbuf)

|__从参数cookie_netfs_data的到struct ceph_fs_client数据结构

|__调用memcpy()函数将struct ceph_fs_client数据结构中的client->fsid值复制到buffer中

 

ceph_readpage_from_fscache(struct inode *inode, struct page *page)

|__从参数inode得到struct ceph_inode_info数据结构

|__调用fscache_read_or_alloc_page()函数从fscache中读取inode的内容并写到page中

 

ceph_readpages_from_fscache(struct inode *inode, struct address_space *mapping, struct list_head *pages, unsigned *nr_pages)

|__从参数inode得到struct ceph_inode_info数据结构

|__调用fscache_read_or_alloc_pages()函数从fscahe中读取mapping中的数据并写入到pages中

 

ceph_readpage_to_fscache(struct inode *inode, struct page *page)

|__从参数inode得到struct ceph_inode_info数据结构

|__调用fscache_write_page()函数将物理内存页page中的数据同步到fscache中

 

ceph_invalidate_fscache_page(struct inode *inode, struct page *page)

|__从参数inode得到struct ceph_inode_info数据结构

|__调用fscache_wait_on_page_write()函数等待page写入完成

|__调用fscache_uncache_page()函数将page中的内容从struct ceph_inode_info中的fscache中删除

 

ceph_fscache_revalidate_cookie(struct ceph_inode_info *ci)

|__调用cache_valid()函数检查ci指定的fscache是否有效,若无效

    |__调用fscache_check_consistency()函数校验ci->fscache的一致性,若不一致

        |__调用fscache_invalidate()函数设置ci->fscache无效

    |__设置ci->i_fscache_gen=ci->i_rdcache_gen

 

关于移植facebook flashcache模块支持 linux kernel 4.13以上facebook install download的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于Apache Cassandra 在 Facebook 的应用、cephfs linux kernel client 针对 fscache 的操作、cephfs linux kernel client 针对 linux page cache 的操作、cephfs linux kernel client针对fscache的操作等相关知识的信息别忘了在本站进行查找喔。

本文标签: