1. 背景
Ceph librbd是QEMU进程的一个依赖库,QEMU通过librbd接口实现虚机磁盘io,当librbd升级或者漏洞修复时需要重启QEMU进程。为了能在QEMU运行时动态修复内存中的librbd问题代码,保障客户业务的连续性,经过大量的研究和实践,构建了基于libcareplus的ceph librbd的“热补丁”技术。
2. 生成热补丁流程
Libcareplus有一套工具,可以很方便的生成热补丁,对于简单的工程直接应用生成热补丁工具是没有问题的,但是对于ceph这样的比较大的工程,需要做一些改变,以适应libcareplus的生成热补丁工具的流程。
2.1. 修改g++和strip路径
Libcareplus默认编译器是用的gcc和低版本的strip,librbd需要用高版本的g++和strip编译,所以需要修改libcareplus的编译器路径。
g++是修改kpatch_cc.c里的realgcc变量。
strip是修改pkgbuild和libcare-patch-make里的strip路径。
2.2. 指定librbd的编译器为libcareplus
通过DCMAKE_CXX_COMPILER=/libcareplus_path/libcare-cc,将librbd的编译器指定为libcareplus的编译,只有这样,才可以用libcareplus的工具生成热补丁。
参考命令:
./do_cmake.sh -DCMAKE_CXX_COMPILER=/root/libcareplus/src/libcare-cc
这里需要注意的是,第一次编译时需要将“libcare-cc”软链接成“g++”,因为第一次会编译boost等一些依赖,需要先用g++编译(注意不用编译全部的ceph,只编译librbd就行)。
参考命令:
mv src/libcare-cc src/libcare-cc.bak
ln -s /opt/rh/devtoolset-8/root/usr/bin/c++ src/libcare-cc
第一次编译完成后再将“libcare-cc”改成真正的“libcare-cc”。
参考命令:
rm -f src/libcare-cc
mv src/libcare-cc.bak src/libcare-cc
2.3. 生成热补丁
上面的步骤准备好后,用“diff -up”生成一个补丁文件。然后就可以用“libcare-patch-make”工具生成librbd的热补丁了。
参考命令:
cd build/src/librbd
diff -up 修改前文件 修改后文件 > BugTest.patch
/root/libcareplus/src/libcare-patch-make -i 热补丁名字 -j 4 BugTest.patch
3. 应用热补丁遇到的问题
在生成热补丁后应用时,遇到了一些问题,在此给大家分享下。
3.1. 生成的热补丁加载后没生效
可以生成热补丁后,在测试过程中,发现加载热补丁命令成功了,但是热补丁代码没有生效,当时是通过添加输出日志判断的。通过“readelf -S”查看了生成热补丁的librbd.so和目标环境的librbd.so,发现是text段的地址不一样。
解决办法是找到需要热升级的ceph版本的tar包和编译环境。在同样的编译环境和使用相同的tar包,这样生成的热补丁才可以用。
3.2. 加载热补丁命令失败
在测试中发现,有时候执行热补丁加载命令,会提示失败。这是因为,加载热补丁时,会遍历虚机里的所有线程,这时虚机里的某个线程销毁时,会导致加载失败,这是正常逻辑,不是libcareplus的bug。
解决办法是可以通过shell脚本,在加载失败时,重试一定次数。