前言

如果用cephfs比较多,应该都知道,在cephfs的客户端进行mount以后,看到的容量显示的是集群的总的容量,也就是你的总的磁盘空间是多少这个地方显示的就是多少

这个一直都是这样显示的,我们之前在hammer版本的时候,阿茂和大黄一起在公司内部实现了这个功能,社区会慢慢的集成一些类似的面向面向商业用户的需求

社区已经开发了一个版本,接口都做的差不多了,那么稍微改改,就能实现想要的需求的

本篇内的改动是基于内核客户端代码的改动,改动很小,应该能够看的懂

改动过程

首先找到这个补丁

Improve accuracy of statfs reporting for Ceph filesystems comprising exactly one data pool. In this case, the Ceph monitor can now report the space usage for the single data pool instead of the global data for the entire Ceph cluster. Include support for this message in mon_client and leverage it in ceph/super.

地址:https://www.spinics.net/lists/ceph-devel/msg37937.html

这个说的是改善了statfs的显示,这个statfs就是在linux下面的mount的输出的显示的,说是改善了在单存储池下的显示效果,也就是在单存储池下能够显示存储池的容量空间,而不是全局的空间

这里就有个疑问了,单存储池?那么多存储池呢?我们测试下看看

这里这个补丁已经打到了centos7.5的默认内核里面去了,也就是内核版本

Linux lab103 3.10.0-862.el7.x86_64

对应的rpm包的版本是

[root@lab103 ceph]# rpm -qa|grep  3.10.0-862
kernel-devel-3.10.0-862.el7.x86_64
kernel-3.10.0-862.el7.x86_64

下载的地址为:

http://mirrors.163.com/centos/7.5.1804/os/x86_64/Packages/kernel-3.10.0-862.el7.x86_64.rpm

或者直接安装centos7.5也行,这里只要求是这个内核就可以了

我们看下默认情况下是怎样的

[root@lab102 ~]# ceph -s
data:
pools: 3 pools, 72 pgs
objects: 22 objects, 36179 bytes
usage: 5209 MB used, 11645 GB / 11650 GB avail
pgs: 72 active+clean [root@lab102 ~]# ceph fs ls
name: ceph, metadata pool: metadata, data pools: [data ]
[root@lab102 ~]# ceph df
GLOBAL:
SIZE AVAIL bash USED %bash USED
11650G 11645G 5209M 0.04
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
data 9 0 0 3671G 0
metadata 10 36179 0 11014G 22
newdata 11 0 0 5507G 0
[root@lab102 ~]# ceph osd dump|grep pool
pool 9 'data' replicated size 3 min_size 1 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 136 flags hashpspool stripe_width 0 application cephfs
pool 10 'metadata' replicated size 1 min_size 1 crush_rule 0 object_hash rjenkins pg_num 32 pgp_num 32 last_change 112 flags hashpspool stripe_width 0 application cephfs
pool 11 'newdata' replicated size 2 min_size 1 crush_rule 0 object_hash rjenkins pg_num 8 pgp_num 8 last_change 134 flags hashpspool stripe_width 0 application cephfs

从上面可以看到我的硬盘裸空间为12T左右,data存储池副本3那么可用空间为4T左右,文件系统里面只有一个data存储池,看下挂载的情况

[root@lab101 ~]# uname -a
Linux lab101 3.10.0-862.el7.x86_64 #1 SMP Fri Apr 20 16:44:24 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
[root@lab101 ~]# df -Th|grep mnt
192.168.19.102:/ ceph 3.6T 0 3.6T 0% /mnt

可以看到显示的容量就是存储池的可用容量为总空间的,现在我们加入一个数据池

[root@lab102 ~]# ceph mds add_data_pool newdata
added data pool 11 to fsmap

再次查看df的显示

[root@lab101 ~]# df -Th|grep mnt
192.168.19.102:/ ceph 12T 5.1G 12T 1% /mnt

容量回到了原始的显示的方式,这个跟上面的补丁的预期是一样的,我们看下代码这里怎么控制的

获取当前内核版本的代码

首先要找到当前的内核的src.rpm包,这样可以拿到当前内核版本的源码

wget http://vault.centos.org/7.5.1804/os/Source/SPackages/kernel-3.10.0-862.el7.src.rpm

解压源码包

[root@lab103 origin]# rpm2cpio kernel-3.10.0-862.el7.src.rpm |cpio -div
[root@lab103 origin]# tar -xvf linux-3.10.0-862.el7.tar.xz
[root@lab103 origin]# cd linux-3.10.0-862.el7/fs/ceph/

上面的操作后我们已经进入了我们想要看的源码目录了

我们看下super.c这个文件,这个df的显示的控制是在这个文件里面的

[root@lab103 ceph]# cat super.c |less

看下这段代码

static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
struct ceph_monmap *monmap = fsc->client->monc.monmap;
struct ceph_statfs st;
u64 fsid;
int err;
u64 data_pool; if (fsc->mdsc->mdsmap->m_num_data_pg_pools == 1) {
data_pool = fsc->mdsc->mdsmap->m_data_pg_pools[0];
} else {
data_pool = CEPH_NOPOOL;
} dout("statfs\n");
err = ceph_monc_do_statfs(&fsc->client->monc, data_pool, &st);
if (err < 0)
return err;

其中的fsc->mdsc->mdsmap->m_num_data_pg_pools == 1和data_pool = fsc->mdsc->mdsmap->m_data_pg_pools[0];这个地方的意思是如果fs里面包含的存储池的存储池个数为1那么data_pool就取这个存储池的信息,所以上面的我们的实践过程中的就是单个存储池的时候显示存储池的容量,超过一个的时候就显示的全局的容量,这个是跟代码对应的上的

我们基于上面的已经做好的功能改变一下需求

需要可以根据自己的需要指定存储池的容量来显示,通过挂载内核客户端的时候传递一个参数进去来进行显示

代码改动

[root@lab103 ceph]# vim super.h

在super.h内定义一个默认值

#define ZP_POOL_DEFAULT      0  /* pool id */
#define CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT 60 /* cap release delay */
struct ceph_mount_options {
int flags;
int sb_flags; int wsize; /* max write size */
int rsize; /* max read size */
int zp_pool; /* pool id */
int rasize; /* max readahead */

这里增加了两个一个zp_pool和ZP_POOL_DEFAULT

这个文件的改动就只有这么多了

改动super.c的代码

在enum里面加上Opt_zp_pool

enum {
Opt_wsize,
Opt_rsize,
Opt_rasize,
Opt_caps_wanted_delay_min,
Opt_zp_pool,

在match_table_t fsopt_tokens里面添加Opt_zp_pool相关的判断,我们自己注意传的是pool在fs里面的id即可

static match_table_t fsopt_tokens = {
{Opt_wsize, "wsize=%d"},
{Opt_rsize, "rsize=%d"},
{Opt_rasize, "rasize=%d"},
{Opt_caps_wanted_delay_min, "caps_wanted_delay_min=%d"},
{Opt_zp_pool, "zp_pool=%d"},

在static int parse_fsopt_token中添加

case Opt_caps_wanted_delay_max:
if (intval < 1)
return -EINVAL;
fsopt->caps_wanted_delay_max = intval;
break;
case Opt_zp_pool:
if (intval < 0)
return -EINVAL;
fsopt->zp_pool = intval;
break;
case Opt_readdir_max_entries:
if (intval < 1)
return -EINVAL;
fsopt->max_readdir = intval;
break;

判断如果小于0就抛错,这个id从0开始上升的,所以也不允许小于0

在static int parse_mount_options中添加

 fsopt->caps_wanted_delay_min = CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT;
fsopt->zp_pool = ZP_POOL_DEFAULT;
fsopt->caps_wanted_delay_max = CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT;

在static int ceph_show_options中添加

        if (fsopt->caps_wanted_delay_min != CEPH_CAPS_WANTED_DELAY_MIN_DEFAULT)
seq_printf(m, ",caps_wanted_delay_min=%d",
fsopt->caps_wanted_delay_min);
if (fsopt->zp_pool)
seq_printf(m, ",zp_pool=%d",
fsopt->zp_pool);
if (fsopt->caps_wanted_delay_max != CEPH_CAPS_WANTED_DELAY_MAX_DEFAULT)
seq_printf(m, ",caps_wanted_delay_max=%d",
fsopt->caps_wanted_delay_max);

这个是用来在执行mount命令的时候显示选项的数值的

改动到这里我们检查下我们对super.c做过的的改动

[root@lab103 ceph]# cat super.c |grep zp_pool
Opt_zp_pool,
{Opt_zp_pool, "zp_pool=%d"},
case Opt_zp_pool:
fsopt->zp_pool = intval;
fsopt->zp_pool = ZP_POOL_DEFAULT;
if (fsopt->zp_pool)
seq_printf(m, ",zp_pool=%d",
fsopt->zp_pool);

做了以上的改动后我们就可以把参数给传进来了,现在我们需要把参数传递到需要用的地方

也就是static int ceph_statfs内需要调用这个参数

在static int ceph_statfs中添加上struct ceph_mount_options *fsopt = fsc->mount_options;

static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct ceph_fs_client *fsc = ceph_inode_to_client(dentry->d_inode);
struct ceph_monmap *monmap = fsc->client->monc.monmap;
struct ceph_statfs st;
struct ceph_mount_options *fsopt = fsc->mount_options;
u64 fsid;

然后改掉这个fsc->mdsc->mdsmap->m_num_data_pg_pools == 1的判断,我们判断大于0即可

        if (fsc->mdsc->mdsmap->m_num_data_pg_pools > 0) {
data_pool = fsc->mdsc->mdsmap->m_data_pg_pools[fsopt->zp_pool];
} else {
data_pool = CEPH_NOPOOL;
}

并且把写死的0改成我们的变量fsopt->zp_pool

到这里改动就完成了,这里还没有完,我们需要编译成我们的需要的模块

[root@lab103 ceph]# modinfo ceph
filename: /lib/modules/3.10.0-862.el7.x86_64/kernel/fs/ceph/ceph.ko.xz

可以看到内核在高版本的时候已经改成了xz压缩的模块了,这里等会需要多处理一步

我们只需要这一个模块就编译这一个ceph.ko模块就好

编译需要装好kernel-devel包kernel-devel-3.10.0-862.el7.x86_64

[root@lab103 ceph]# pwd
/home/origin/linux-3.10.0-862.el7/fs/ceph
[root@lab103 ceph]# make CONFIG_CEPH_FS=m -C /lib/modules/3.10.0-862.el7.x86_64/build/ M=`pwd` modules
make: Entering directory `/usr/src/kernels/3.10.0-862.el7.x86_64'
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/super.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/inode.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/dir.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/file.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/locks.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/addr.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/ioctl.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/export.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/caps.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/snap.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/xattr.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/mds_client.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/mdsmap.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/strings.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/ceph_frag.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/debugfs.o
CC [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/acl.o
LD [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/ceph.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/origin/linux-3.10.0-862.el7/fs/ceph/ceph.mod.o
LD [M] /home/origin/linux-3.10.0-862.el7/fs/ceph/ceph.ko
make: Leaving directory `/usr/src/kernels/3.10.0-862.el7.x86_64'

正常应该就是上面的没有报错的输出了

压缩ko模块

[root@lab103 ceph]# find * -name '*.ko' | xargs -n 1 xz
[root@lab103 ceph]# rmmod ceph
[root@lab103 ceph]# rm -rf /lib/modules/3.10.0-862.el7.x86_64/kernel/fs/ceph/ceph.ko.xz
[root@lab103 ceph]# cp -ra ceph.ko.xz /lib/modules/3.10.0-862.el7.x86_64/kernel/fs/ceph/
[root@lab103 ceph]# lsmod |grep ceph
ceph 345111 0
libceph 301687 1 ceph
dns_resolver 13140 1 libceph
libcrc32c 12644 2 xfs,libceph

现在已经加载好模块了,我们试验下

[root@lab103 ceph]# ceph df
GLOBAL:
SIZE AVAIL bash USED %bash USED
11650G 11645G 5210M 0.04
POOLS:
NAME ID USED %USED MAX AVAIL OBJECTS
data 9 0 0 3671G 0
metadata 10 36391 0 11014G 22
newdata 11 0 0 5507G 0 [root@lab103 ceph]# mount -t ceph 192.168.19.102:/ /mnt
[root@lab103 ceph]# df -h|grep mnt
192.168.19.102:/ 3.6T 0 3.6T 0% /mnt
[root@lab103 ceph]# ceph fs ls
name: ceph, metadata pool: metadata, data pools: [data newdata ]

我们给了一个默认存储池的值为0的编号的,现在显示的是data的容量,没有问题,我们想显示newdata存储池的

[root@lab103 ceph]# mount -t ceph 192.168.19.102:/ /mnt -o zp_pool=1
[root@lab103 ceph]# df -h|grep mnt
192.168.19.102:/ 5.4T 0 5.4T 0% /mnt

这里我们显示的要么0,要么1的存储池的那么我如果想显示全局的怎么处理?那就是给个不存在的编号就行了

[root@lab103 ceph]# mount -t ceph 192.168.19.102:/ /mnt -o zp_pool=1000
[root@lab103 ceph]# mount|grep ceph|grep zp_pool
192.168.19.102:/ on /mnt type ceph (rw,relatime,acl,wsize=16777216,zp_pool=1000)
[root@lab103 ceph]# df -h|grep mnt
192.168.19.102:/ 12T 5.1G 12T 1% /mnt

也可以自己去改成读取all字段的时候取全局变量,这个是直接用一个不存在的编号去走到全局的容量的逻辑里面去了,这样比较简单

通过mount命令可以查询到挂载的选项

到这里就根据需求改完了

总结

本篇里面涉及的知识点包括了rpm包的源码的获取,解压,以及内核模块的单独编译,改动单个模块进行替换,cephfs客户端的内核参数的自定义传递等等,在本博客的第三篇文章就有一个单独编译一个ext4模块的

变更记录

Why Who When
创建 武汉-运维-磨渣 2018-08-20

cephfs根据存储池显示df容量的更多相关文章

  1. ceph的df容量显示计算

    显示数据 [root@lab201 ~]# ceph df GLOBAL: SIZE AVAIL RAW USED %RAW USED 1092T 404T 688T 63.01% POOLS: NA ...

  2. Linux学习之CentOS(十三)-----磁盘管理之 磁盘与目录的容量(转) df 与du 命令

    磁盘与目录的容量 现在我们知道磁盘的整体数据是在 superblock 区块中,但是每个各别文件的容量则在 inode 当中记载的. 那在文字接口底下该如何叫出这几个数据呢?底下就让我们来谈一谈这两个 ...

  3. Linux常用命令学习7---(磁盘管理df du、磁盘的分区和格式化fdisk parted)

    1.磁盘管理    在服务器的维护中,我们需要关心服务器的磁盘使用了多少.还有多少的剩余空间.某个文件有多大.某个文件夹内的所有文件在一起一共占用的多少空间……问题.以便我们在合适的时机为服务器添加硬 ...

  4. 磁盘与目录的容量[转自vbird]

    磁盘与目录的容量 现在我们知道磁盘的整体数据是在 superblock 区块中,但是每个各别文件的容量则在 inode 当中记载的. 那在文字接口底下该如何叫出这几个数据呢?底下就让我们来谈一谈这两个 ...

  5. 文件系统常用命令df、du、fsck、dumpe2fs

    df 查看文件系统 [root@localhost ~]# df 文件系统 1K-块 已用 可用 已用% 挂载点 /dev/sda5 16558080 1337676 15220404 9% / de ...

  6. Linux文件系统的简单操作 - df, du, ln

    现在我们知道磁盘的整体数据是在 superblock 区块中,但是每个各别文件的容量则在 inode 当中记载的. 那在文字接口底下该如何叫出这几个数据呢?底下就让我们来谈一谈这两个命令: df:列出 ...

  7. linux命令学习之:df

    df命令用于显示磁盘分区上的可使用的磁盘空间.默认显示单位为KB.可以利用该命令来获取硬盘被占用了多少空间,目前还剩下多少空间等信息. 语法 df (选项) (参数) 选项 -a或--all:包含全部 ...

  8. Linux学习总结(七)-磁盘管理 du df fdisk

    一 命令df df,即disk free,可用来查看当前系统的挂载情况,也可以用来查看整体磁盘的使用情况df 不带参数,默认以KB单位显示df -i -----查看inodes 使用情况,要清楚理解i ...

  9. linux之df命令

    介绍: Linux中df命令可以用来显示目前在Linux系统上的文件系统的磁盘使用情况统计.这些工具可以方便地知道哪些文件系统消耗多少内存.此外,如果被拾起,并且提供一个特定的文件名作为df命令的参数 ...

随机推荐

  1. 多层级makefile

    多层级makefile 当项目变大之后,需要多层级的makefile来编译,每个makefile的具体功能实现参考单源文件目录makefile.然后再在顶层目录写一个总的makefile来实现编译逻辑 ...

  2. xuexi0.1

    1.C语言通过编译器对内存进行了一定的封装.a +=4等效于a=a+4.C语言中数据类型的本质含义:表示一个内存格子的长度和解析方法.(int *)0:表示0是一个指针,这个指针指向一个int类型的数 ...

  3. spring boot: 用redis的消息订阅功能更新应用内的caffeine本地缓存(spring boot 2.3.2)

    一,为什么要更新caffeine缓存? 1,caffeine缓存的优点和缺点 生产环境中,caffeine缓存是我们在应用中使用的本地缓存, 它的优势在于存在于应用内,访问速度最快,通常都不到1ms就 ...

  4. Linux安装软件时90%的人会遇到这个报错,如何解决?

    提示 Could not get lock /var/lib/dpkg/lock 报错? 有些小伙伴在使用 apt 包管理器更新或安装软件时,可能会遇到过诸如以下的错误提示: E: Could not ...

  5. 想买保时捷的运维李先生学Java性能之 运行时数据区域

    前言 不知道自己不知道,不知道自己知道,知道自己不知道,知道自己知道,目前处于知道自己不知道这个阶段,很痛苦啊,干了4年了运维,是一个坎.越来越发觉想要走得远,还是得扎根底.   一.运行时数据区域 ...

  6. CF1430 E. String Reversal(div 2)

    题目链接:http://codeforces.com/contest/1430/problem/E 题意:有一串长度为n(n<=2*10^5)由小写字母组成的字符串,求通过相邻交换得到其反转串( ...

  7. 实战四:Gateway网关作全局路由转发

    Gateway网关的作用主要是两个:路由转发,请求过滤.此篇讲的是路由转发,下篇介绍请求过滤. 一,创建网关module,添加依赖 1,new -> module -> maven 或直接 ...

  8. 12 Servlet_04 Servlet增删改查 静态页面与动态页面 EL表达式 table表格的一些样式

    今天学习了servlet的增删改查: 存储数据 setAttribute(String name,Object obj );获取数据 getAttribute(String name);删除数据 re ...

  9. pycharm配置django rest framework

    安装django rest framework pip install 添加rest_framework app  在settings.py INSTALLED_APPS = [ 'django.co ...

  10. 小白如何学习PyTorch】25 Keras的API详解(下)缓存激活,内存输出,并发解决

    [新闻]:机器学习炼丹术的粉丝的人工智能交流群已经建立,目前有目标检测.医学图像.时间序列等多个目标为技术学习的分群和水群唠嗑答疑解惑的总群,欢迎大家加炼丹兄为好友,加入炼丹协会.微信:cyx6450 ...