zoukankan      html  css  js  c++  java
  • 内核补丁热更新ceph内核模块

    前言

    内核模块的更新一般需要卸载模块再加载,但是很多时候使用场景决定了无法做卸载的操作,而linux支持了热更新内核模块的功能,这个已经支持了有一段时间了,一直没有拿ceph的相关模块进行验证

    注意模块的某些函数是不支持的,init的部分是不支持的,补丁弄完验证一下就可以知道支不支持,不支持的部分会提示

    准备工作

    先检查当前的版本支持不

    [root@lab101 kpatch]# cat /boot/config-3.10.0-1062.el7.x86_64 |grep PATCH
    CONFIG_HAVE_LIVEPATCH=y
    CONFIG_LIVEPATCH=y
    CONFIG_DVB_BUDGET_PATCH=m
    CONFIG_SND_HDA_PATCH_LOADER=y
    

    可以看到默认内核是支持的,这个是红帽维护的一个体系,自己的内核,肯定会很快集成进去的

    安装依赖包

    [root@lab102 ~]# yum install  elfutils-devel  rpm-build
    [root@lab102 ~]# rpm -ivh kernel-debuginfo-common-x86_64-3.10.0-1062.el7.x86_64.rpm kernel-debuginfo-3.10.0-1062.el7.x86_64.rpm
    

    下载软件

    git clone https://github.com/dynup/kpatch.git
    make 
    make install 
    

    上面的软件提供两个命令
    一个是kpatch
    一个是kpatch-build
    后面会用到

    我的机器是这个版本

    [root@lab102 ~]# uname  -a
    Linux lab102 3.10.0-1062.el7.x86_64 #1 SMP Wed Aug 7 18:08:02 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
    

    那么提前下载好

    kernel-3.10.0-1062.el7.src.rpm
    

    生成差异热更新模块

    因为这个打补丁是基于差异打的补丁,所以需要知道之前的源码和现在的源码的差异,然后再进行后面的处理,所以我们要准备两份源码,一份未修改的,一份修改了的

    [root@lab102 kernel]# rpm2cpio kernel-3.10.0-1062.el7.src.rpm |cpio -div
    [root@lab102 kernel]# xz -d linux-3.10.0-1062.el7.tar.xz
    [root@lab102 kernel]# tar -xvf linux-3.10.0-1062.el7.tar
    [root@lab102 kernel]# cp -ra linux-3.10.0-1062.el7/ linux-3.10.0-1062.el7-patch
    

    我们现在就有两份源码了
    我们默认使用的是前面那套内核里面的代码,后面的是准备修改的代码

    修改代码

    [root@lab102 kernel]# vim linux-3.10.0-1062.el7-patch/drivers/block/rbd.c 
    

    为了方便查看我们修改rbd map的函数

            pr_info("%s: capacity %llu features 0x%llx
    ", rbd_dev->disk->disk_name,
                    (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
                    rbd_dev->header.features);
            rc = count;
    

    改成

           pr_info("%s: capacity 我改这里的显示了  %llu features 0x%llx
    ", rbd_dev->disk->disk_name,
                    (unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
                    rbd_dev->header.features);
            rc = count;
    
    

    获取差异文件

    [root@lab102 kernel]#  diff -u linux-3.10.0-1062.el7/drivers/block/rbd.c linux-3.10.0-1062.el7-patch/drivers/block/rbd.c > rbd.patch
    

    得到的文件如下

    [root@lab102 kernel]# cat rbd.patch 
    --- linux-3.10.0-1062.el7/drivers/block/rbd.c	2019-07-19 03:58:03.000000000 +0800
    +++ linux-3.10.0-1062.el7-patch/drivers/block/rbd.c	2020-11-19 15:22:21.653239816 +0800
    @@ -6299,7 +6299,7 @@
     	list_add_tail(&rbd_dev->node, &rbd_dev_list);
     	spin_unlock(&rbd_dev_list_lock);
     
    -	pr_info("%s: capacity %llu features 0x%llx
    ", rbd_dev->disk->disk_name,
    +	pr_info("%s: capacity 我改这里的显示了  %llu features 0x%llx
    ", rbd_dev->disk->disk_name,
     		(unsigned long long)get_capacity(rbd_dev->disk) << SECTOR_SHIFT,
     		rbd_dev->header.features);
     	rc = count;
    
    

    我们需要根据这个

    [root@lab102 kernel]# /usr/local/bin/kpatch-build rbd.patch  --skip-gcc-check --skip-cleanup  -r kernel-3.10.0-1062.el7.src.rpm
    WARNING: Skipping gcc version matching check (not recommended)
    Skipping cleanup
    Fedora/Red Hat distribution detected
    Downloading kernel source for 3.10.0-1062.el7.x86_64
    Unpacking kernel source
    Testing patch file(s)
    Reading special section data
    Building original source
    Building patched source
    Extracting new and modified ELF sections
    rbd.o: changed function: do_rbd_add.isra.45
    Patched objects: drivers/block/rbd.ko
    Building patch module: livepatch-rbd.ko
    SUCCESS
    

    可以从提示上面看到一些信息
    修改是drivers/block/rbd.ko模块,改了do_rbd_add这个函数,生成得是livepatch-rbd.ko这个ko文件

    我们把这个ko文件拷贝到相同内核的,需要更新的机器

    先做map的操作,检查打补丁前的输出

    [root@lab101 patch]# rbd map testrbd
    /dev/rbd0
    [root@lab101 patch]# dmesg 
    [3303179.423310] libceph: mon0 192.168.19.101:6789 session established
    [3303179.423726] libceph: client20564 fsid beeb1bd5-54ed-40b6-897f-f31f43a517e6
    [3303179.429378] rbd: rbd0: capacity 53687091200 features 0x1
    
    [root@lab101 patch]# kpatch list
    Loaded patch modules:
    Installed patch modules:
    

    可以看到没有打过补丁

    加载补丁

    [root@lab101 patch]# kpatch load livepatch-rbd.ko 
    loading patch module: livepatch-rbd.ko
    waiting (up to 15 seconds) for patch transition to complete...
    transition complete (3 seconds)
    

    尝试map

    [root@lab101 patch]# rbd map testrbda
    /dev/rbd1
    [root@lab101 patch]# dmesg 
    [3303179.423310] libceph: mon0 192.168.19.101:6789 session established
    [3303179.423726] libceph: client20564 fsid beeb1bd5-54ed-40b6-897f-f31f43a517e6
    [3303179.429378] rbd: rbd0: capacity 53687091200 features 0x1
    [3303262.296794] livepatch: enabling patch 'livepatch_rbd'
    [3303262.307782] livepatch: 'livepatch_rbd': starting patching transition
    [3303264.938241] livepatch: 'livepatch_rbd': patching complete
    [3303291.798301] rbd: rbd1: capacity 我改这里的显示了  53687091200 features 0x1
    [root@lab101 patch]# kpatch list
    Loaded patch modules:
    livepatch_rbd [enabled]
    
    Installed patch modules:
    

    可以看到上面的操作过程中我并没有去rmmod rbd 或者重新modprobe rbd,内核模块就已经更新了

    上面的是加载了补丁,如果需要安装补丁是需要执行

    [root@lab101 patch]# kpatch install livepatch-rbd.ko 
    installing livepatch-rbd.ko (3.10.0-1062.el7.x86_64)
    Created symlink from /etc/systemd/system/multi-user.target.wants/kpatch.service to /usr/local/lib/systemd/system/kpatch.service.
    

    实际上上面的操作是把patch的ko拷贝到了路径

    /var/lib/kpatch/3.10.0-1062.el7.x86_64/livepatch-rbd.ko
    

    install的操作就是启动的时候把这个加载进去
    如果觉得不满意,补丁是支持回退的

    [root@lab101 patch]# kpatch unload livepatch-rbd
    disabling patch module: livepatch_rbd
    waiting (up to 15 seconds) for patch transition to complete...
    transition complete (3 seconds)
    unloading patch module: livepatch_rbd
    

    基于以上就完成了rbd的一次热更新的过程了,通常来说模块的更新并不需要重启机器,但是如果模块提供的服务上面加载了其它服务,服务又被客户端连接的话,这个更新步骤就比较麻烦了,如果能够热更新,能够省很多事情,当然内核模块的更新要测试验证没有问题再去动,否则很容易把机器搞死机了

    自有内核模块的热更新

    如果内核模块是自己改过的,或者并不是内核树里面的,需要打补丁,可以用下面的命令处理

    /usr/local/bin/kpatch-build -s ./block/ -t all -e ./block/rbd.ko block-rbd.patch  --skip-gcc-check
    

    上面的block为源码的目录,需要准备好Makefile的,后面的-e后面接的是之前版本编译出来的内核模块,block-rbd.patch 就是源码的差异,然后编译出来的就是patch模块
    这个地方内核的版本就再block的里面的Makefile里面去控制了

    [root@lab102 kernel]# /usr/local/bin/kpatch-build -s ./block/ -t all -e ./block/rbd.ko block-rbd.patch  --skip-gcc-check
    WARNING: Skipping gcc version matching check (not recommended)
    Using source directory at /root/kernel/block
    Testing patch file(s)
    Reading special section data
    Building original source
    Building patched source
    Extracting new and modified ELF sections
    rbd.o: changed function: do_rbd_add.isra.45
    Patched objects: rbd.ko
    Building patch module: livepatch-block-rbd.ko
    SUCCESS
    

    这个方式的编译就快很多了,如果是更新内核自带的模块,用上面的整个编译的,如果是自己改过的,就可以用后面的方式去实现了

  • 相关阅读:
    并发编程(IO多路复用)
    411. 格雷编码
    120. 单词接龙 (BFS)
    1244. Minimum Genetic Mutation
    47.Majority Element I & II
    86. 二叉查找树迭代器
    1183. 排序数组中的单个元素
    163. 不同的二叉查找树
    428.x的n次幂
    156. 合并区间
  • 原文地址:https://www.cnblogs.com/zphj1987/p/14006711.html
Copyright © 2011-2022 走看看