前言

如果用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. 编程语言那么多,为什么偏偏是C语言成了大学的必修课?

    谁叫你不幸生在中国了?--何祚庥(中国科学院院士) 这是一本给非计算机专业的大学生的C语言的书."我不是学计算机的,为啥要学C语言?"这个问题每年在中华大地都会被问上几百万次. 被 ...

  2. 【C语言/C++程序员编程】一小时做出来的数字雨(一颗开花的树)!

    相信大家看过许许多多的关于计算机黑客.骇客.人工智能.AI方面的电影,每当黑客入侵某个五角大楼,某个网站时,都会出现这样一副画面: 入侵 或者这样的: 数字雨 然后就轻而易举的成功入侵夺取管理员权限了 ...

  3. jquery1.9+,jquery1.10+ 为什么不支持live方法了?

    live() 替换成 on() die()  替换成off() 根据jQuery的官方描述,live方法在1.7中已经不建议使用,在1.9中删除了这个方法.并建议在以后的代码中使用on方法来替代. o ...

  4. web功能测试

    web功能测试基础: https://www.cnblogs.com/wz123/p/9680484.html

  5. MySQL备份和恢复[2]-基于LVM的快照备份

    准备工作 请求锁定所有表 mysql> FLUSH TABLES WITH READ LOCK; 记录二进制日志文件及事件位置 mysql> FLUSH LOGS; mysql> S ...

  6. CentOS8 yum安装Mariadb10.4

    CentOS8 yum安装Mariadb10.4 https://downloads.mariadb.org/mariadb/repositories/#distro=CentOS&distr ...

  7. HashMap的理解

    Hashmap的实现原理 默认它是存放了16个链表头的数组,存储数据的时候key先生成hashcode,根据hashcode把数据存放到相应链表中,那么是如何确定存放到哪个链表中的呢?采用hashco ...

  8. Django采坑日志(django2.0)

    使用Mariadb时出现的问题 "Unknown system variable 'transaction_isolation'" 解决办法:修改django/db/backend ...

  9. 「IDEA插件精选」安利一个IDEA骚操作:一键生成方法的序列图

    在平时的学习/工作中,我们会经常面临如下场景: 阅读别人的代码 阅读框架源码 阅读自己很久之前写的代码. 千万不要觉得工作就是单纯写代码,实际工作中,你会发现你的大部分时间实际都花在了阅读和理解已有代 ...

  10. 【2】TensorFlow光速入门-数据预处理(得到数据集)

    本文地址:https://www.cnblogs.com/tujia/p/13862351.html 系列文章: [0]TensorFlow光速入门-序 [1]TensorFlow光速入门-tenso ...