建立你自己的內核模塊
英文版本由 AkemiYagi 建立。現時由 AlanBartlett 及 AkemiYagi 維護。
請注意,假若你修改你的內核,你將不再穫得 CentOS 開發小組的支援或幫助。這裡所描述的步驟並沒有 CentOS 的官方認可。這個教學文檔的原意是要幫助你建立自己的內核模塊。 |
要是你將會在採用 Secure Boot 的系統上安裝自己的模塊,你須要以私鑰簽署該模塊。詳情見 Signing Kernel Modules for Secure Boot。 |
本教學文檔以 CentOS-7 作為範例操作系統。
在某些情況下你也許會需要更改或建立一個新的內核模塊。也許你要加入某個功能,或者只是做一個修正。在這件教學文檔內,我們會嘗試將一個錯誤修正加進現有的模塊內,然後安裝它。
這裡假設你已經安裝了整個內核的源代碼。如果你是按照「我需要內核的源代碼」的第 2 部份,它會位於 ~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0.`uname -m`/ 這個目錄內。
我們強烈地反對你以 root 用戶來建立模塊。(見:Building Source RPM as non-root under CentOS)
1. 建立一個內核模塊(*.ko)
設我們假設,作為一個範例,你將會針對位於 ~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0-957.x86_64/fs/cifs/ 目錄內的 cif 模塊加入修正。
1. 針對源代碼檔進行所需的修正。
2. 進到內核源代碼的主目錄。如果這次是內核首次被編譯,請設定內核,並謹記在設定檔(.conf)內將相關的元件設為模塊。
[user@host]$ cd ~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0-957.x86_64 [user@host linux-3.10.0-957.x86_64]$ make oldconfig [user@host linux-3.10.0-957.x86_64]$ make prepare
3. 建立編譯外置模塊時所需的檔案。
[user@host linux-3.10.0-957.x86_64]$ make modules_prepare
4. 透過指定模塊的 Makefile 及源代碼的相對路徑來編譯模塊。
[user@host linux-3.10.0-957.x86_64]$ make M=fs/cifs
註:藏有模塊的目錄可以位於任何一個位置。舉個例說,假如它位於 ~/mycifs/,你可以在內核源代碼的主目錄裡執行以下的指令:
[user@host linux-3.10.0-957.x86_64]$ make M=~/mycifs
5. 除非你編譯這個模塊作偵錯用途,否則你應該移除不必要的符號。
[user@host linux-3.10.0-957.x86_64]$ strip --strip-debug fs/cifs/cifs.ko
6. 這個範例建立了 cifs.ko 這個檔案。請以 root 的身份將 .ko 檔案複製到 /lib/modules/<內核版本>/extra/ 目錄內。
[root@host linux-3.10.0-957.x86_64]# cp fs/cifs/cifs.ko /lib/modules/`uname -r`/extra
7. 以 root 的身份執行 depmod 指令來更新模塊的依賴檔。
[root@host linux-3.10.0-957.x86_64]# depmod -a
2. 利用動態內核模塊支援(DKMS)建立一個內核模塊
上面所描述的方法是為某個特定的內核版本建立一個模塊。一旦你將內核升級或者更改硬件的架構,你將會須要將模塊重新建立。動態內核模塊支援(DKMS)這個架構基本上是在內核源代碼以外的地方複製一棵目錄樹,當中藏有某個模塊的源代碼及編譯了的二進制程式。DKMS 可以用來建立、安裝及解除安裝模塊。DKMS 需要在系統上找到模塊的源代碼。DKMS 程式庫亦能代你建立及安裝模塊到你系統上的任何內核裡。
在這裡我們會採用與上面相同的範例來建立及安裝 cifs 這個模塊。在下面整個部份,你都須要有 root 的權限。
1. 安裝所有與這個模塊的目標內核版本相乎的 kernel-devel 套件。
2. 安裝 EPEL 軟件庫(見 軟件庫頁)內的 dkms 套件。
3. 建立一個 /usr/src/<模塊>-<模塊版本>/ 的目錄
[root@host]# mkdir /usr/src/cifs-1.45fixed/
4. 將模塊的源代碼複製到這個目錄。
[root@host]# cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18-i686/fs/cifs [root@host cifs]# cp -a * /usr/src/cifs-1.45fixed/
5. 在 /usr/src/<模塊>-<模塊版本>/ 這個目錄內建立 dkms.conf 檔
[root@host cifs]# cd /usr/src/cifs-1.45fixed [root@host cifs-1.45fixed]# vi dkms.conf
dkms.conf 檔須要包含以下內容:
PACKAGE_NAME="cifs" PACKAGE_VERSION="1.45fixed" BUILT_MODULE_NAME[0]="cifs" DEST_MODULE_LOCATION[0]="/kernel/fs/cifs/" AUTOINSTALL="yes"
註:DEST_MODULE_LOCATION[0] 這一行將會在安裝模塊時被忽視,因為它一定會是 /lib/modules/<內核版本>/extra/ 這個目錄。然而,這個參數卻指定當模塊被解除安裝時,舊有被儲存的模塊(假若有的話)應該被還原到哪個位置。
6. 將 <模塊>/<模塊版本> 加進 DKMS 的目錄樹。
[root@host cifs-1.45fixed]# dkms add -m cifs -v 1.45fixed
7. 在 DKMS 的控制下編譯模塊。
[root@host cifs-1.45fixed]# dkms build -m cifs -v 1.45fixed
8. 在 DKMS 的控制下安裝模塊。
[root@host cifs-1.45fixed]# dkms install -m cifs -v 1.45fixed
其它值得注意的 DKMS 動作包括 uninstall、remove、status 及 mkrpm。它們分別會將模塊從內核移除,將 <模塊>/<模塊版本> 從 DKMS 目錄樹移除,顯示 DKMS 的現時狀況,及在 /var/lib/dkms/<模塊>/<模塊版本>/rpm/ 這個目錄內建立一個 rpm 檔案。
請亦參閱:
3. 建立一個內核模塊的 rpm 套件(kmod)
你亦可以為內核模塊建立 rpm 檔案。這個內核模塊的套件(kmod)便可以像其它套件一樣透過 rpm 指令來安裝。然而,包裝內核模塊的 rpm 與標準的包裝過程有不同的處理方法。以下的範例提供了基本的內核模塊 rpm 包裝技巧。
再一次,我們會以 cifs 模塊作為範例來建立一套 kmod-cifs 的 rpm 檔。
1. 安裝所有對應你現有內核的 kernel-devel 套件。
2. 正如上面的第 1 部份,已修正的源代碼位於 ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/fs/cifs/ 這個目錄內。請複製這個目錄。
[user@host]$ mkdir ~/cifs-1.45/ [user@host]$ cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/fs/cifs [user@host]$ cp -a * ~/cifs-1.45/
3. 建立一個藏有來源目錄的 bzip2 壓縮檔。
[user@host]$ cd [user@host]$ tar -jcf cifs-1.45.tar.bz2 cifs-1.45/
4. 將壓縮檔複製到 SOURCES 目錄內。
[user@host]$ cp cifs-1.45.tar.bz2 ~/rpmbuild/SOURCES/
5. 複製 kmodtool 這個腳本(它是 redhat-rpm-config 套件的一部份)到 SOURCES 目錄內。
[user@host]$ cd ~/rpmbuild/SOURCES/ [user@host SOURCES]$ cp /usr/lib/rpm/redhat/kmodtool kmodtool-cifs-el5.sh
6. 編輯你所複製的 kmodtool-cifs-el5.sh 檔案,並確定當中提及 kmod-common 的行都被改為註釋。然後加入一行在 %files 內會擴充成指向 kmod-cifs.conf 檔的指令。
[user@host SOURCES]$ vi kmodtool-cifs-el5.sh
由第 105 行起 ——
# # RHEL5 - Remove common package requirement on general kmod packages. # Requires: ${kmod_name}-kmod-common >= %{?epoch:%{epoch}:}%{version} #
由第 168 行起 ——
echo "%files -n kmod-${kmod_name}${dashvariant}" if [ "" == "$kmp_override_filelist" ]; then echo "%defattr(644,root,root,755)" echo "/lib/modules/${verrel}${variant}/" echo "%config /etc/depmod.d/kmod-${kmod_name}.conf" #BZ252188 - I've commented this out for the moment since RHEL5 doesn't # really support external firmware e.g. at install time. If # you really want it, use an override filelist solution. #echo "/lib/firmware/" else cat "$kmp_override_filelist" fi
7. 在 SPECS 目錄內建立 cifs-kmod.spec 檔。
[user@host SOURCES]$ cd ~/rpmbuild/SPECS/ [user@host SPECS]$ vi cifs-kmod.spec
# Define the kmod package name here. %define kmod_name cifs # If kversion isn't defined on the rpmbuild line, define it here. %{!?kversion: %define kversion 2.6.18-8.el5} Name: %{kmod_name}-kmod Version: 1.45 Release: 1%{?dist} Group: System Environment/Kernel License: GPLv2 Summary: %{kmod_name} kernel module(s) URL: http://www.centos.org/ BuildRequires: redhat-rpm-config BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-build-%(%{__id_u} -n) ExclusiveArch: i686 x86_64 # Sources. Source0: %{kmod_name}-%{version}.tar.bz2 Source10: kmodtool-%{kmod_name}-el5.sh # Define the variants for each architecture. %define basevar "" %ifarch i686 %define paevar PAE %endif %ifarch i686 x86_64 %define xenvar xen %endif # If kvariants isn't defined on the rpmbuild line, build all variants for this architecture. %{!?kvariants: %define kvariants %{?basevar} %{?xenvar} %{?paevar}} # Magic hidden here. %{expand:%(sh %{SOURCE10} rpmtemplate_kmp %{kmod_name} %{kversion} %{kvariants})} # Disable the building of the debug package(s). %define debug_package %{nil} # Define the filter. %define __find_requires sh %{_builddir}/%{buildsubdir}/filter-requires.sh %description This package provides the CentOS-5 bug-fixed %{kmod_name} kernel module (bug #1776). It is built to depend upon the specific ABI provided by a range of releases of the same variant of the Linux kernel and not on any one specific build. %prep %setup -q -c -T -a 0 for kvariant in %{kvariants} ; do %{__cp} -a %{kmod_name}-%{version} _kmod_build_$kvariant done echo "/usr/lib/rpm/redhat/find-requires | %{__sed} -e '/^ksym.*/d'" > filter-requires.sh echo "override %{kmod_name} * weak-updates/%{kmod_name}" > kmod-%{kmod_name}.conf %build for kvariant in %{kvariants} ; do KSRC=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu} %{__make} -C "${KSRC}" %{?_smp_mflags} modules M=$PWD/_kmod_build_$kvariant done %install %{__rm} -rf %{buildroot} export INSTALL_MOD_PATH=%{buildroot} export INSTALL_MOD_DIR=extra/%{kmod_name} for kvariant in %{kvariants} ; do KSRC=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu} %{__make} -C "${KSRC}" modules_install M=$PWD/_kmod_build_$kvariant done %{__install} -d %{buildroot}%{_sysconfdir}/depmod.d/ %{__install} kmod-%{kmod_name}.conf %{buildroot}%{_sysconfdir}/depmod.d/ # Set the module(s) to be executable, so that they will be stripped when packaged. find %{buildroot} -type f -name \*.ko -exec %{__chmod} u+x \{\} \; %clean %{__rm} -rf %{buildroot} %changelog * Wed Jan 05 2011 Alan Bartlett <ajb@elrepo.org> - 1.45 - Revised this specification file. * Fri May 18 2007 Akemi Yagi <toracat@centos.org> - 1.45 - Initial el5 build of the kmod package.
8. 建立套件。
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` cifs-kmod.spec 2> build-err.log | tee build-out.log
你果你不想建立一個對應使用中的內核的 kmod 套件,你可以在指令行上指定內核的版本。例如:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --define 'kversion 2.6.18-371.el5' cifs-kmod.spec 2> build-err.log | tee build-out.log
這樣做便會為 2.6.18-371.el5 內核建立 kmod 套件。
在 CentOS 7 及內含 kmodtool 腳本的較新版本,請用以下方式提供內核版本
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --define 'kernel_version 3.10.0-862.el7' cifs-kmod.spec 2> build-err.log | tee build-out.log
這樣做便會為 3.10.0-862.el7 內核建立 kmod 套件。
利用同一個方法,你可以選擇建立哪一個內核類型的 kmod 套件。例如:
[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --define 'kvariants ""' cifs-kmod.spec 2> build-err.log | tee build-out.log
這樣做便只會建立基本內核的 kmod 套件。
當編譯完成後,~/rpmbuild/RPMS/`uname -m`/ 目錄內將會藏有一套 kmod-cifs 的 rpm 檔。
請亦參閱:
以 RHEL 6 為基礎的 Red Hat 驅動程式更新套件官方參考指南 http://people.redhat.com/jcm/el6/dup/docs/dup_book.pdf
Fedora 的建設一般 rpm 文檔 https://docs.fedoraproject.org/en-US/quick-docs/creating-rpm-packages/
已棄用的 Fedora 文檔有關如何建立內核模塊套件,純作參考之用。 http://fedoraproject.org/wiki/Obsolete/KernelModules
Translation of revision 170