前言

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

准备工作

先检查当前的版本支持不

[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\n", 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\n", 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\n", rbd_dev->disk->disk_name,
+ pr_info("%s: capacity 我改这里的显示了 %llu features 0x%llx\n", 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

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

最新文章

  1. 那些年我们学过的构造函数(构造方法,C#)
  2. 在博文中嵌入Javascript代码
  3. HTML滚动字幕代码参数详解及Js间隔滚动代码
  4. 卸载oracle
  5. Tkinter教程之Checkbutton篇
  6. Find Median from Data Stream 解答
  7. typecho博客出404页面修改方法
  8. 利用cookies获取登录后的网页
  9. How To Compile Qt with Visual Studio 2010
  10. html5 PACS漫谈
  11. 【JVM命令系列】jstat
  12. 【Python实践-4】切片操作去除字符串首尾的空格
  13. springboot自动生成mysql的DAO层代码
  14. 安装系统后IP配置问题
  15. ElasticSearch5.4.1 搜索引擎搭建文档
  16. python网络编程(三)
  17. JDBC 中preparedStatement和Statement区别
  18. Linux基础知识与基础命令
  19. linux command ------ watch
  20. FTP下载工具

热门文章

  1. Python错误:AssertionError: group argument must be None for now
  2. js后台提交成功后 关闭当前页 并刷新父窗体
  3. uvalive6468,51cthink1419 Strange Antennas (离散化)
  4. JUC---01阻塞队列(BlockingQueue)
  5. 走在深夜的小码农 Seventh Day
  6. drf 认证校验及源码分析
  7. sqlsugar入门(3)-DateTime.ToString(&quot;yyyy-MM-dd HH:mm:ss.fff&quot;)源码修改
  8. NB-IoT的PSM模式有什么优点
  9. OpenCascade拓扑对象之:TopoDS_Shape对象及其子对象
  10. python模块导入(包)