内核补丁热更新ceph内核模块
内核补丁热更新ceph内核模块
zphj1987前言
内核模块的更新一般需要卸载模块再加载,但是很多时候使用场景决定了无法做卸载的操作,而linux支持了热更新内核模块的功能,这个已经支持了有一段时间了,一直没有拿ceph的相关模块进行验证
注意模块的某些函数是不支持的,init的部分是不支持的,补丁弄完验证一下就可以知道支不支持,不支持的部分会提示
准备工作
先检查当前的版本支持不
1 | [root@lab101 kpatch]# cat /boot/config-3.10.0-1062.el7.x86_64 |grep PATCH |
可以看到默认内核是支持的,这个是红帽维护的一个体系,自己的内核,肯定会很快集成进去的
安装依赖包
1 | [root@lab102 ~]# yum install elfutils-devel rpm-build |
下载软件
1 | git clone https://github.com/dynup/kpatch.git |
上面的软件提供两个命令
一个是kpatch
一个是kpatch-build
后面会用到
我的机器是这个版本
1 | [root@lab102 ~]# uname -a |
那么提前下载好
1 | kernel-3.10.0-1062.el7.src.rpm |
生成差异热更新模块
因为这个打补丁是基于差异打的补丁,所以需要知道之前的源码和现在的源码的差异,然后再进行后面的处理,所以我们要准备两份源码,一份未修改的,一份修改了的
1 | [root@lab102 kernel]# rpm2cpio kernel-3.10.0-1062.el7.src.rpm |cpio -div |
我们现在就有两份源码了
我们默认使用的是前面那套内核里面的代码,后面的是准备修改的代码
修改代码
1 | [root@lab102 kernel]# vim linux-3.10.0-1062.el7-patch/drivers/block/rbd.c |
为了方便查看我们修改rbd map的函数
1 | pr_info("%s: capacity %llu features 0x%llx\n", rbd_dev->disk->disk_name, |
改成
1 | pr_info("%s: capacity 我改这里的显示了 %llu features 0x%llx\n", rbd_dev->disk->disk_name, |
获取差异文件
1 | [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 |
得到的文件如下
1 | [root@lab102 kernel]# cat rbd.patch |
我们需要根据这个
1 | [root@lab102 kernel]# /usr/local/bin/kpatch-build rbd.patch --skip-gcc-check --skip-cleanup -r kernel-3.10.0-1062.el7.src.rpm |
可以从提示上面看到一些信息
修改是drivers/block/rbd.ko模块,改了do_rbd_add这个函数,生成得是livepatch-rbd.ko这个ko文件
我们把这个ko文件拷贝到相同内核的,需要更新的机器
先做map的操作,检查打补丁前的输出
1 | [root@lab101 patch]# rbd map testrbd |
可以看到没有打过补丁
加载补丁
1 | [root@lab101 patch]# kpatch load livepatch-rbd.ko |
尝试map
1 | [root@lab101 patch]# rbd map testrbda |
可以看到上面的操作过程中我并没有去rmmod rbd 或者重新modprobe rbd,内核模块就已经更新了
上面的是加载了补丁,如果需要安装补丁是需要执行
1 | [root@lab101 patch]# kpatch install livepatch-rbd.ko |
实际上上面的操作是把patch的ko拷贝到了路径
1 | /var/lib/kpatch/3.10.0-1062.el7.x86_64/livepatch-rbd.ko |
install的操作就是启动的时候把这个加载进去
如果觉得不满意,补丁是支持回退的
1 | [root@lab101 patch]# kpatch unload livepatch-rbd |
基于以上就完成了rbd的一次热更新的过程了,通常来说模块的更新并不需要重启机器,但是如果模块提供的服务上面加载了其它服务,服务又被客户端连接的话,这个更新步骤就比较麻烦了,如果能够热更新,能够省很多事情,当然内核模块的更新要测试验证没有问题再去动,否则很容易把机器搞死机了
自有内核模块的热更新
如果内核模块是自己改过的,或者并不是内核树里面的,需要打补丁,可以用下面的命令处理
1 | /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里面去控制了
1 | [root@lab102 kernel]# /usr/local/bin/kpatch-build -s ./block/ -t all -e ./block/rbd.ko block-rbd.patch --skip-gcc-check |
这个方式的编译就快很多了,如果是更新内核自带的模块,用上面的整个编译的,如果是自己改过的,就可以用后面的方式去实现了