核心補丁熱更新ceph核心模組

磨渣發表於2020-11-19

前言

核心模組的更新一般需要解除安裝模組再載入,但是很多時候使用場景決定了無法做解除安裝的操作,而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\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

這個方式的編譯就快很多了,如果是更新核心自帶的模組,用上面的整個編譯的,如果是自己改過的,就可以用後面的方式去實現了

相關文章