Differences between revisions 72 and 73

Deletions are marked like this. Additions are marked like this.
Line 8: Line 8:
||<class="lmimg blue" style="padding: 0pt;"> [[ImageLink(ArtWork/WikiDesign/icon-admonition-info.png)]] ||||<class="lmtxt blue" style="padding: 0pt; text-align: left; vertical-align: top;">要是你將會在採用 Secure Boot 的系統上安裝自己的模塊,你須要以私鑰簽署該模塊。詳情見 [https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Kernel_Administration_Guide/sect-signing-kernel-modules-for-secure-boot.html Signing Kernel Modules for Secure Boot]。||
Line 10: Line 12:
/!\ 本教學文檔以 CentOS-5 作為範例操作系統。雖然 CentOS-5 已不再獲支援,以下所記載的程序仍然有效。 /!\ 本教學文檔以 CentOS-7 作為範例操作系統。
Line 14: Line 16:
這裡假設你已經安裝了整個內核的源代碼。如果你是按照[:zh-tw/HowTos/I need the Kernel Source:「我需要內核的源代碼」]的第 2 部份,它會位於 `~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.`{{{`uname -m`}}}`/` 這個目錄內。這份教學文檔亦假設系統是 32 位元的架構。因此 {{{`uname -m`}}} 所傳回的字串是 i686,而以上的目錄將會是 `~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/`。 這裡假設你已經安裝了整個內核的源代碼。如果你是按照[:zh-tw/HowTos/I need the Kernel Source:「我需要內核的源代碼」]的第 2 部份,它會位於 `~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0.`{{{`uname -m`}}}`/` 這個目錄內。
Line 20: Line 22:
設我們假設,作為一個範例,你將會針對位於 `~/rpmbuild/BUILD/kernel-2.6.18/linux-2.6.18.i686/fs/cifs/` 目錄內的 cif 模塊加入修正。 設我們假設,作為一個範例,你將會針對位於 `~/rpmbuild/BUILD/kernel-3.10.0/linux-3.10.0-957.x86_64/fs/cifs/` 目錄內的 cif 模塊加入修正。
Line 27: Line 29:
[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
[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
Line 35: Line 36:
[user@host linux-2.6.18.i686]$ make modules_prepare
}}}
註:就算 CONFIG_MODULEVERSIONING 這個參數已被設定,''make modules_prepare'' 仍然不會建立 Module.symvers 檔。因此你必須事先重建整個內核,然後模塊版本的功能才會生效。欲知詳情,請參閱 `/usr/share/doc/kernel-doc-2.6.18/Documentation/kbuild/modules.txt` 內的 #2.4 及 #7 部份。
[user@host linux-3.10.0-957.x86_64]$ make modules_prepare
}}}
Line 42: Line 42:
[user@host linux-2.6.18.i686]$ make M=fs/cifs [user@host linux-3.10.0-957.x86_64]$ make M=fs/cifs
Line 47: Line 47:
[user@host linux-2.6.18.i686]$ make M=~/mycifs [user@host linux-3.10.0-957.x86_64]$ make M=~/mycifs
Line 52: Line 52:
[user@host linux-2.6.18.i686]$ strip --strip-debug fs/cifs/cifs.ko [user@host linux-3.10.0-957.x86_64]$ strip --strip-debug fs/cifs/cifs.ko
Line 57: Line 57:
[root@host linux-2.6.18.i686]# cp fs/cifs/cifs.ko /lib/modules/`uname -r`/extra
}}}
要知道更多關於模塊安裝用的目錄,請參閱 `/usr/share/doc/kernel-doc-2.6.18/Documentation/kbuild/modules.txt` 內的 #6 部份。
[root@host linux-3.10.0-957.x86_64]# cp fs/cifs/cifs.ko /lib/modules/`uname -r`/extra
}}}
Line 64: Line 63:
[root@host linux-2.6.18.i686]# depmod -a
}}}
8. 還有數個步驟是用來建立不同類型的內核的模塊。請編輯'''內核源代碼的主目錄'''內的 Makefile。在 CentOS 5 上,請找尋:

{{{
EXTRAVERSION = -prep
}}}
然後(按你的情況)取代為:

{{{
EXTRAVERSION = -419.el5
EXTRAVERSION = -419.el5PAE
EXTRAVERSION = -419.el5xen
EXTRAVERSION = -419.el5.centos.plus
EXTRAVERSION = -419.el5.centos.plusPAE
EXTRAVERSION = -419.el5.centos.plusxen
}}}
### 如果你將會用 modprobe 來安裝模塊,這個數字並不重要。(一個 `-371.el5` 模塊可以安裝在一個 `-371.12.1.el5` 內核上,如此類推)。'''但你必須有 PAE 及 xen 的修飾詞才能應用在這類型內核上'''。

提示:當你為標準內核編譯好模塊後,編輯 `EXTRAVERSION` 這行來加入 '''PAE''' 或 '''xen''',然後執行 `make modules_prepare`。接著執行 `make M=xxx` 來編譯 `EXTRAVERSION` 所指定的內核版本的模塊。
[root@host linux-3.10.0-957.x86_64]# depmod -a
}}}
Line 333: Line 314:
~-Translation of revision 165-~ ~-Translation of revision 168-~

建立你自己的內核模塊

英文版本由 AkemiYagi 建立。現時由 AlanBartlettAkemiYagi 維護。

請注意,假若你修改你的內核,你將不再穫得 CentOS 開發小組的支援或幫助。這裡所描述的步驟並沒有 CentOS 的官方認可。這個教學文檔的原意是要幫助你建立自己的內核模塊。

/ArtWork/WikiDesign?action=AttachFile&do=get&target=ArtWork/WikiDesign/icon-admonition-info.png

要是你將會在採用 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 動作包括 uninstallremovestatusmkrpm。它們分別會將模塊從內核移除,將 <模塊>/<模塊版本> 從 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 檔。

請亦參閱:

Translation of revision 168

zh-tw/HowTos/BuildingKernelModules (last edited 2019-08-08 10:08:00 by TimothyLee)