分享

HowTos/BuildingKernelModules

 jijo 2009-12-15

There are occasions when you need to modify a kernel module or create a new one. This may be to add certain features or simply to apply a patch. In this tutorial, we will attempt to apply a bug fix to an existing module and then install it.

It is assumed that you already have the full kernel source tree installed. If you followed Section 2 of I need the Kernel Source, it will be found in the directory ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`uname -m`/. Throughout this tutorial a system with 32-bit architecture is assumed. Hence the string returned by `uname -m` is i686 and the directory referenced above will be ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/.

<!> You are strongly advised against performing module building as root. (See: Building Source RPM as non-root under CentOS)

1. Building a kernel module (*.ko)

Let us assume, as an example, you are applying a patch to the cifs module which is located in the ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/fs/cifs/ directory.

1. Apply the patch(es) to the source file(s) as required.

2. Change to the root directory of the kernel source and, if this is the first time the kernel has been compiled, configure the kernel remembering to ensure that the relevant component of the kernel is set, within its configuration file (.conf), to be built as a module.

[user@host]$ cd ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686
[user@host linux-2.6.18.i686]$ make oldconfig
[user@host linux-2.6.18.i686]$ make menuconfig
[user@host linux-2.6.18.i686]$ make prepare

3. Create the files required for compiling external modules.

[user@host linux-2.6.18.i686]$ make modules_prepare

Note: make modules_prepare will not build a Module.symvers file even if the parameter CONFIG_MODULEVERSIONING has been set. Therefore a full kernel build will have to have been executed previously to make module versioning work. For more details, see Sections #2.4 & #7 of /usr/share/doc/kernel-doc-2.6.18/Documentation/kbuild/modules.txt

4. Compile the module by specifying the relative path to the module’s Makefile and source code.

[user@host linux-2.6.18.i686]$ make M=fs/cifs

Note: The whole directory containing the module can be located anywhere. If, for example, it is in ~/mycifs/ run the following command making sure that you are still in the root directory of the kernel source.

[user@host linux-2.6.18.i686]$ make M=~/mycifs

5. Unless you have compiled this module for debugging purposes, it should now be stripped of unnecessary symbols.

[user@host linux-2.6.18.i686]$ strip --strip-debug fs/cifs/cifs.ko

6. In this example, the file cifs.ko has just been created. As root, copy the .ko file to the /lib/modules/<kernel-version>/extra/ directory.

[root@host linux-2.6.18.i686]# cp fs/cifs/cifs.ko /lib/modules/`uname -r`/extra

For further details of the directories into which modules are installed, see Section #6 of /usr/share/doc/kernel-doc-2.6.18/Documentation/kbuild/modules.txt

7. As root, run the depmod command to update the module dependency files.

[root@host linux-2.6.18.i686]# depmod -a

8. A further few steps are required to build the different modules for the different types of kernel. Edit the main Makefile in the root directory of the kernel source. For CentOS 5, find:

EXTRAVERSION = -prep

and replace it with (as appropriate):

EXTRAVERSION = -164.6.1.el5
EXTRAVERSION = -164.6.1.el5PAE
EXTRAVERSION = -164.6.1.el5xen
EXTRAVERSION = -164.6.1.el5.centos.plus
EXTRAVERSION = -164.6.1.el5.centos.plusPAE
EXTRAVERSION = -164.6.1.el5.centos.plusxen

The number is not very important if you are going to use modprobe to install the module. (A -164.el5 module will install into a -164.6.1.el5 kernel, etc.). However the PAE and xen modifiers are required to be used for those types of kernels.

Hint: After compiling the module for the standard kernel, edit the EXTRAVERSION line to add PAE or xen and run make modules_prepare. Then run make M=xxx to compile the module for the kernel version specified on the EXTRAVERSION line.

2. Building a kernel module using Dynamic Kernel Module Support (DKMS)

The method described above builds a module for a particular kernel version. If you upgrade the kernel or change the hardware architecture, you will have to manually build the module once again. The dynamic kernel module support (DKMS) framework is basically a duplicate tree, outside of the kernel source, that holds the source and compiled binaries for a particular module. DKMS can be called on to build, install or uninstall modules. DKMS requires the module source code to be located on your system. The DKMS binary takes care of building and installing the module(s) into any kernel(s) you may have on your system.

Here we will use the same example as above and build & install the cifs module. You will need to assume root's powers for this entire section.

1. Install the kernel-devel package that matches your current kernel.

2. Install the dkms package from the Repositories/RPMForge repository.

3. Create a directory /usr/src/<module>-<module-version>/

[root@host]# mkdir /usr/src/cifs-1.45fixed/

4. Copy the module's source code to that directory.

[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. Create a dkms.conf file in the directory /usr/src/<module>-<module-version>/

[root@host cifs]# cd /usr/src/cifs-1.45fixed
[root@host cifs-1.45fixed]# vi dkms.conf

The dkms.conf file will need to contain these lines:

PACKAGE_NAME="cifs"
PACKAGE_VERSION="1.45fixed"
BUILT_MODULE_NAME[0]="cifs"
DEST_MODULE_LOCATION[0]="/kernel/fs/cifs/"
AUTOINSTALL="yes"

Note: The DEST_MODULE_LOCATION[0] line will be ignored during module installation because this will always be to the /lib/modules/<kernel-version>/extra/ directory. This parameter, however, will be used when a module is uninstalled as the location to which the stored, old module (if any) will be restored.

6. Add the <module>/<module-version> to the DKMS tree.

[root@host cifs-1.45fixed]# dkms add -m cifs -v 1.45fixed

7. Compile the module, under DKMS control.

[root@host cifs-1.45fixed]# dkms build -m cifs -v 1.45fixed

8. Install the module, again under DKMS control.

[root@host cifs-1.45fixed]# dkms install -m cifs -v 1.45fixed

Other DKMS actions to note are uninstall, remove, status and mkrpm which uninstalls the module from the kernel, removes the <module>/<module-version> from the DKMS tree, displays the current DKMS status of the system and creates a rpm file in the directory /var/lib/dkms/<module>/<module-version>/rpm/ respectively.

See also:

3. Building a kernel module rpm package (kmod)

You can also create rpm files for kernel modules. The kernel module rpm package (kmod) may then be installed by using the rpm command just like any other package. However, rpm packaging of kernel modules is handled differently from the standard packaging process. The example, below, provides the basic kernel module rpm packaging technique.

Once again we will use the cifs module as an example and create a set of kmod-cifs rpm files.

1. Install all the kernel-devel packages for your current kernel.

2. The patched source code is in the ~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/fs/cifs/ directory as in Section 1, above. Make a working copy of that directory.

[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. Create a bzip2 compressed tarball containing the source directory.

[user@host]$ cd
[user@host]$ tar -jcf cifs-1.45.tar.bz2 cifs-1.45/

4. Copy the compressed tarball to the SOURCES directory.

[user@host]$ cp cifs-1.45.tar.bz2 ~/rpmbuild/SOURCES/

5. Make a copy the script kmodtool (part of the redhat-rpm-config package) in the SOURCES directory.

[user@host]$ cd ~/rpmbuild/SOURCES/
[user@host SOURCES]$ cp /usr/lib/rpm/redhat/kmodtool kmodtool-cifs

6. Edit your copy of the kmodtool-cifs file to ensure that the line referencing kmod-common is commented out and to add a line that expands to become a reference to a cifs.conf file under the %files section.

[user@host SOURCES]$ vi kmodtool-cifs

Line 105 onwards --

#
# RHEL5 - Remove common package requirement on general kmod packages.
# Requires: ${kmod_name}-kmod-common >= %{?epoch:%{epoch}:}%{version}
#

Line 168 onwards --

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_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. Create a cifs-kmod.spec file in the SPECS directory.

[user@host SOURCES]$ cd ~/rpmbuild/SPECS/
[user@host SPECS]$ vi cifs-kmod.spec

# Define the kmod package name here.
%define  kmod_name cifs
#
Name:    %{kmod_name}-kmod
Version: 1.45
Release: 1.el5
Group:   System Environment/Kernel
License: GPL v2
Summary: CentOS-5 bug-fixed cifs module
URL:     http://www./
#
BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-build-%(%{__id_u} -n)
ExclusiveArch: i686 x86_64
#
# Sources.
Source0:  %{kmod_name}-%{version}.tar.bz2
Source10: kmodtool-%{kmod_name}
#
# If kversion isn't defined on the rpmbuild line, build for the current kernel.
%{!?kversion: %define kversion %(uname -r)}
#
# 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.
%define kmodtool sh %{SOURCE10}
%{expand:%(%{kmodtool} rpmtemplate_kmp %{kmod_name} %{kversion} %{kvariants} 2>/dev/null)}
#
%description
This package provides the CentOS-5 bug-fixed cifs 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 CentOS 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
    %{__cat} <<-EOF >_kmod_build_$kvariant/%{kmod_name}.conf
        override %{kmod_name} * weak-updates/%{kmod_name}
        EOF
done
#
%build
for kvariant in %{kvariants} ; do
    ksrc=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu}
    pushd _kmod_build_$kvariant
    %{__make} -C "${ksrc}" modules M=$PWD
    popd
done
#
%install
export INSTALL_MOD_PATH=$RPM_BUILD_ROOT
export INSTALL_MOD_DIR=extra/%{kmod_name}
for kvariant in %{kvariants} ; do
    ksrc=%{_usrsrc}/kernels/%{kversion}${kvariant:+-$kvariant}-%{_target_cpu}
    pushd _kmod_build_$kvariant
    %{__make} -C "${ksrc}" modules_install M=$PWD
    %{__install} -d ${INSTALL_MOD_PATH}/etc/depmod.d/
    %{__install} %{kmod_name}.conf ${INSTALL_MOD_PATH}/etc/depmod.d/
    popd
done
# Strip the module(s).
find ${INSTALL_MOD_PATH} -type f -name \*.ko -exec strip --strip-debug \{\} \;
#
%clean
%{__rm} -rf $RPM_BUILD_ROOT
#
%changelog
* Mon Aug 17 2009 Alan Bartlett <ajb@elrepo.org>
- Revised the kmodtool file and this spec file.
#
* Thu May 14 2009 Alan Bartlett <ajb@elrepo.org>
- Refined this spec file.
#
* Fri Mar 20 2009 Alan Bartlett <ajb@elrepo.org>
- Added a line to strip the modules.
#
* Thu Dec 25 2008 Alan Bartlett <ajb@elrepo.org>
- Re-aligned this spec file to RHEL standards.
#
* Sat Dec 13 2008 Alan Bartlett <ajb@elrepo.org>
- Added a .el5 identifier to the release.
#
* Tue Jul 29 2008 Alan Bartlett <ajb@elrepo.org>
- Revised this specification file.
#
* Fri May 18 2007 Akemi Yagi <toracat@>
- Initial example kmod specification file.

8. Build the package.

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` cifs-kmod.spec 2> build-err.log | tee build-out.log

If you do not wish to build the kmod packages for your currently running kernel, you can specify the the kernel version on the command line. For example:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --define 'kversion 2.6.18-164.el5' cifs-kmod.spec 2> build-err.log | tee build-out.log

will build the kmod packages for the 2.6.18-164.el5 kernel.

In a similar fashion, you may select which kernel-variant kmod package(s) to build. For example:

[user@host SPECS]$ rpmbuild -bb --target=`uname -m` --define 'kvariants ""' cifs-kmod.spec 2> build-err.log | tee build-out.log

will build just the base-kernel kmod package.

When the build completes, there will be a set of kmod-cifs rpm files in the ~/rpmbuild/RPMS/`uname -m`/ directory.

See also:


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多