在这篇文章中,我们将带领您了解移植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)
- 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)
环境
准备在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 的应用
谁说 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 的操作
针对 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 的操作
针对 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的操作
针对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的操作等相关知识的信息别忘了在本站进行查找喔。
本文标签: