创建你自己的内核模块
英文版本由 AkemiYagi 创建。现时由 AlanBartlett 及 AkemiYagi 维护。
请注意,假若你修改你的内核,你将不再获得 CentOS 开发小组的支持或帮助。这里所描述的步骤并没有 CentOS 的官方认可。这个教学文档的原意是要帮助你创建自己的内核模块。 |
要是你将会在采用 Secure Boot 的系统上安装自己的模块,你须要以私钥签署该模块。详情见 Signing Kernel Modules for Secure Boot。 |
本教学文档以 CentOS-5 作为样例操作系统。
在某些情况下你也许会需要更改或创建一个新的内核模块。也许你要加入某个功能,或者只是做一个修正。在这件教学文档内,我们会尝试将一个错误修正加进现有的模块内,然后安装它。
这里假设你已经安装了整个内核的源代码。如果你是按照「我需要内核的源代码」的第 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