Fedora 24: カーネルを再ビルドする

Fedora 24のカーネルのsrc.rpmを使って、カーネルコンフィグとソースコードを変更して、カーネルを再ビルドする手順を記載します。

 

1 カーネルのビルドに必要なパッケージのインストール

dnfでカーネルのビルドに必要なパッケージをインストールします。

$ sudo dnf install -y rpmdevtools
$ sudo dnf install -y numactl-devel pesign
$ sudo dnf builddep -y kernel

2 カーネルのsrc.rpmのダウンロード

カーネルのsrc.rpmをダウンロードします。

$ dnf download --source kernel
$ rpm -i kernel-*.src.rpm
$ cd rpmbuild

3 バージョンの変更

specファイルのbuildid変数に値を設定します。これによりrpmのファイル名だけでなく、カーネルのファイル名も変更されます。

$ diff -uprN SPECS/kernel.spec{.org,}
--- SPECS/kernel.spec.org       2016-06-24 14:59:18.778477097 +0900
+++ SPECS/kernel.spec   2016-06-24 15:01:04.257355709 +0900
@@ -24,7 +24,7 @@ Summary: The Linux kernel
 %global zipsed -e 's/\.ko$/\.ko.xz/'
 %endif

-# define buildid .local
+%define buildid .local

 # baserelease defines which build revision of this kernel version we're
 # building.  We used to call this fedora_build, but the magical name

4 カーネルコンフィグの変更

rpmbuild -bpでソースコードの展開とパッチの適用を実行します。x86_64環境では.configはconfig-x86_64-genericから作られます。

$ rpmbuild -bp SPECS/kernel.spec
$ cd BUILD/kernel-*/linux-*
$ cp .config{,.org}
$ make menuconfig # Change config

この記事ではmake menuconfigでCONFIG_IKCONFIG=yとCONFIG_IKCONFIG_PROC=yを設定します。

General setup  --->
  Kernel .config support # Change to y
    Enable access to .config through /proc/config.gz # Change to y

元々の.configとの差分を確認します。

$ diff -uprN .config{.org,}
--- .config.org 2016-06-24 15:36:48.185480769 +0900
+++ .config     2016-06-24 15:42:39.928537381 +0900
@@ -1,6 +1,6 @@
 #
 # Automatically generated file; DO NOT EDIT.
-# Linux/x86_64 4.5.7 Kernel Configuration
+# Linux/x86 4.5.7 Kernel Configuration
 #
 CONFIG_64BIT=y
 CONFIG_X86_64=y
@@ -147,7 +147,8 @@ CONFIG_RCU_NOCB_CPU=y
 CONFIG_RCU_NOCB_CPU_ALL=y
 # CONFIG_RCU_EXPEDITE_BOOT is not set
 CONFIG_BUILD_BIN2C=y
-# CONFIG_IKCONFIG is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
 CONFIG_LOG_BUF_SHIFT=18
 CONFIG_LOG_CPU_MAX_BUF_SHIFT=12
 CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y

今回は運良くCONFIG_IKCONFIG=yとCONFIG_IKCONFIG_PROC=yをconfig-x86_64-genericに追加すれば良いようです。場合によってはconfig-x86_64-genericからエントリを削除する必要もあるでしょう。

$ cd ../../..
$ echo "CONFIG_IKCONFIG=y" >> SOURCES/config-x86_64-generic
$ echo "CONFIG_IKCONFIG_PROC=y" >> SOURCES/config-x86_64-generic
$ diff -uprN SOURCES/config-x86_64-generic{.org,}
--- SOURCES/config-x86_64-generic.org   2016-06-24 15:31:00.094273529 +0900
+++ SOURCES/config-x86_64-generic       2016-06-24 15:45:57.139900141 +0900
@@ -234,3 +234,5 @@ CONFIG_HFI1_VERBS_31BIT_PSN=y

 # Temporary workaround until SND_SOC_INTEL_HASWELL_MACH no longer requires builtin
 CONFIG_DW_DMAC=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
#+END_SRC

もう一度rpmbuild -bpを実行しコンフィグが反映されているかを確認します。

$ rpmbuild -bp SPECS/kernel.spec
# No error
$ grep -nr 'CONFIG_IKCONFIG' BUILD/kernel-*/linux-*/.config
150:CONFIG_IKCONFIG=y
151:CONFIG_IKCONFIG_PROC=y

5 カーネルソースコードの変更

rpmbuild -bpでソースコードの展開とパッチの適用を実行します。展開されたソースコードはgitリポジトリになっているので、パッチ作成に利用します。

$ rpmbuild -bp SPECS/kernel.spec
$ cd BUILD/kernel-*/linux-*

コンフィグファイル等の変更をリポジトリに取り込みます(ファイルを削除しても良いです)。

$ git add * \.[^\.]* .gitignore
$ git commit -m "Cleanup main branch"
$ git status
On branch master
nothing to commit, working directory clean

パッチを作成するためのブランチを作成します。

$ git checkout master -b hello
Switched to a new branch 'hello'
$ git branch
* hello
  master

ソースコードを変更してコミットします。ここではRAMDISK実行前に"Hello, World"と表示する変更を加えます。

$ # This article changed init/main.c
$ git diff
diff --git a/init/main.c b/init/main.c
index 58c9e37..d1254da 100644
--- a/init/main.c
+++ b/init/main.c
@@ -945,6 +945,8 @@ static int __ref kernel_init(void *unused)

        rcu_end_inkernel_boot();

+       printk("Hello, World\n");
+
        if (ramdisk_execute_command) {
                ret = run_init_process(ramdisk_execute_command);
                if (!ret)
$ git add *
$ git commit -m "Hello, World"
[hello 2fa1c98] Hello, World
 1 file changed, 2 insertions(+)

パッチをSOURCESディレクトリに格納します。

$ git format-patch master --start-number 1000 -o ../../../SOURCES/
../../../SOURCES/1000-Hello-World.patch

kernel.specにパッチのエントリを追加します。

$ diff -uprN SPECS/kernel.spec{.org,}
--- SPECS/kernel.spec.org       2016-06-24 16:45:44.303806793 +0900
+++ SPECS/kernel.spec   2016-06-24 17:45:46.523021602 +0900
@@ -663,6 +663,9 @@ Patch721: tipc-fix-an-infoleak-in-tipc_n
 #CVE-2016-5244 rhbz 1343338 1343337
 Patch722: rds-fix-an-infoleak-in-rds_inc_info_copy.txt

+#Hello, World
+Patch1000: 1000-Hello-World.patch
+
 # END OF PATCH DEFINITIONS

 %endif

カーネルのソースツリーのバックアップを取っておいても良いでしょう。BUILDディレクトリを空にして、再度rpmbuild -bpを実行し、パッチが適用されるかを確認します。

$ # mv BUILD/kernel-*/linux-* ~/
$ rm -rf BUILD/*
$ rpmbuild -bp SPECS/kernel.spec
$ # No error

6 カーネルのビルド

–withoutオプションでビルドするrpmパッケージを絞ります。–withoutオプションありだと3時間ほど掛かります。–withoutオプションなしだと6時間ほど掛かります。

$ rpmbuild -ba --without debug --without doc --without perf \
--without tools --without debuginfo --without kdump \
--without bootwrapper --without cross_headers SPECS/kernel.spec
$ ls RPMS/x86_64/
kernel-4.5.7-300.local.fc24.x86_64.rpm
kernel-core-4.5.7-300.local.fc24.x86_64.rpm
kernel-devel-4.5.7-300.local.fc24.x86_64.rpm
kernel-headers-4.5.7-300.local.fc24.x86_64.rpm
kernel-modules-4.5.7-300.local.fc24.x86_64.rpm
kernel-modules-extra-4.5.7-300.local.fc24.x86_64.rpm
$ sudo dnf install -y RPMS/x86_64/*.rpm
$ sudo reboot

7 動作確認

"Hello, World"と表示されました。

[    1.472560] Freeing unused kernel memory: 164K (ffff8800017d7000 - ffff880001800000)
[    1.475601] Freeing unused kernel memory: 544K (ffff880001b78000 - ffff880001c00000)
[    1.477372] Hello, World
[    1.480600] random: systemd urandom read with 4 bits of entropyavailable
[    1.483575] systemd[1]: systemd 229 running in system
mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP
+LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +SECCOMP +BLKID +ELFUTILS
+KMOD +IDN)

カーネルのバージョンも.localが付きました。

$ uname -r
4.5.7-300.local.fc24.x86_64

/proc/config.gzが見えるようになりました。

$ ls -l /proc/config.gz
-r--r--r--. 1 root root 42418  6月 25 04:03 /proc/config.gz