如何實現內核模塊與內核版本的解耦


   問題背景

    我們當前系統使用的內核版本為A版本,我安裝了一個在B版本內核上編譯的一個模塊catch.ko,A和B兩個內核版本的KABI是兼容的。通過rpm -ql xx_mode可以看到要插入到內核的模塊是放在了lib/modules/B<kernel_version>/extra/目錄下。在/lib/moudles目錄下也多了一個內核目錄。由於KABI是兼容的,所以在B版本上編譯的模塊,在A版本的內核中也可以正常運行。但是當出現這種情況時,模塊的自動加載就需要注意了。

linux:/lib/modules # ls
3.10.0-514.32.3.18_40.x86_64  3.10.0-514.41.4.28_63.x86_64

    正常情況下,如果要內核某模塊在系統啟動時自動加載,需要放在/lib/modules/<uname -r>目錄下,在系統安裝過程中,會通過depmod命令生成模塊間的依賴關系,生成modules.dep modules.dep.bin,而modprobe命令就是依賴於depmod生成的結果來實現模塊自動加載的,在kmod-20-15版本前,depmod只能識別/lib/modules/<kernel version>/目錄下對應的模塊。

    因為catch模塊是放在/lib/modules/B<kernel_version>/extra目錄下,而modprobe命令都是從/lib/modules/A<kernel_version>目錄下去搜索尋找的,所以當使用modprobe catch時,會顯示失敗。那么如何解決這個問題呢?目前方法有兩個:一個是使用weak-modules機制,一個是使用depmod中的externel機制。

一、weak-modules

    Linux weak-modules機制的作用是判斷哪些模塊與當前安裝的內核是kABI兼容的,如果兼容則在當前內核版本中建立該模塊的軟鏈接。weak-modules不僅應用在驅動模塊安裝、升級、卸載上,在安裝系統、升級內核、卸載內核時也會執行該腳本。總之weak-modules機制是用來保證同一個模塊能在kABI兼容的多個內核版本之間共同使用,不必每個版本都發布一個模塊。

    在Redhat和SUSE系統環境常使用RPM包安裝管理軟件,驅動模塊也會使用RPM打包安裝。為了使同一個驅動模塊能夠在多個kABI兼容的內核版本中正常運行,驅動包的post腳本中會執行weak-modules腳本來分析驅動模塊是否兼容,如果兼容則建立軟鏈接,如果滿足一定條件還會刷新initrd文件。是否會刷新initrd文件及刷新條件,不同系統和版本在設計和實現上有所不同。

    Redhat環境下業界標准驅動包的post腳本通過指定--add-modules和模塊名調用weak-modules腳本,如果兼容則在/lib/modules/kernel-version/weak-updates目錄下建立模塊源文件的軟鏈接,源文件則在其他內核版本的/lib/modules/other-kernel -version/extra目錄下。Redhat驅動包通常以kmod-modname-ver-release.xx.arch.rpm命名。SUSE環境下業界標准驅動包的post腳本通過指定--add-kmp和模塊名調用weak-modules2腳本,如果兼容則在/lib/modules/kernel-version/weak-updates目錄下建立模塊源文件的軟鏈接,源文件則在其他內核版本的/lib/modules/other-kernel -version/updates目錄下。SUSE驅動包通常以modname-kmp-flavor-ver-release.arch.rpm命名。這些都是當前現有的做法,不排除在版本演進過程中兩個發行商使用方式歸一或者有新的實現方式。

    Redhat和SUSE系統建立軟鏈接的實現方式上有較大的區別,但主題思路是一樣的,大致如下:weak-modules腳本首先讀取post腳本輸入的模塊參數列表,分析判斷模塊列表中的模塊在各個內核版本中是否是兼容的,如果兼容則建立原始模塊文件的軟鏈接。

    我們以Redhat舉例,在catch這個模塊所屬包的spec文件中,我們在post后面加入如下腳本:

%post -n kmod-catch
echo "/lib/modules/%{kversion}/extra/catch.ko" | /sbin/weak-modules --add-module --no-initramfs

kversion為上文所說的B kernel版本,weak-modules的用法參見 http://linux.51yip.com/search/weak-modules

linux:uname -r
3.10.0-514.41.4.28_63.x86_64
linux:/lib/modules # ls
3.10.0-514.32.3.18_40.x86_64  3.10.0-514.41.4.28_63.x86_64
linux: echo /lib/modules/3.10.0-514.32.3.18_40.x86_64/extra/catch.ko | /sbin/weak-modules --add-module --no-initramfs
linux:/lib/modules/3.10.0-514.41.4.28_63.x86_64/weak-updates/ # ll
total 4
lrwxrwxrwx 1 root root 73 May 26 10:54 catch.ko -> /lib/modules/3.10.0-514.32.3.18_40.x86_64/extra/catch.ko

在weak-updates目錄下生成一個軟鏈接后,在執行modprobe后,就會從這個軟連接找到真正的ko模塊,完成模塊加載。

linux: modprobe catch
linux: modinfo catch.ko
filename:       /lib/modules/3.10.0-514.41.4.28_63.x86_64/weak-updates/catch.ko
license:        GPL

二、depmod.d external

      社區在17年發布一組patch,depmod支持external關鍵字,可以指定文件系統上的任意目錄,depmod會自動識別並進入modules.dep的生成結果中。如上例子,可以將catch.ko放置在其他目錄,如/opt/modules/目錄下,在/etc/depmod.d/目錄下去添加配置文件catch.conf,配置文件寫為:

external 3.10.0-514* /opt/modules

external為depmod的關鍵字,用於指定模塊放置的路徑,3.10.0-514*代表與當前內核版本模糊匹配,當然也要保證這個大版本號的KABI是兼容的。在執行depmod時,會從depmod.d目錄下搜索配置文件,然后根據配置,去/opt/modules目錄下搜索模塊,加入modules.dep的生成結果中。執行modprobe catch后,使用modinfo查詢,可以看到modinfo顯示的文件name已經發生變化:

linux:modinfo signo_catch
filename:       /opt/modules/catch.ko
license:        GPL

另外需要注意的是,在/etc/depmod.d/dist.conf文件中,配置了搜索的路徑和優先級,其中built-in代碼着/lib/modules/<kernel>/kernel目錄下的所有驅動,即內核自帶驅動模塊。

# depmod.conf
#
# override default search ordering for kmod packaging
search updates extra external built-in weak-updates

通過以上兩種方法,就可以完成內核模塊和內核版本之間的耦合關系,即不需要發布一個內核版本,同時發布一個對應的模塊。這樣操作就比較靈活,也減去很多編譯模塊的工作量和時間。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM