Debian/Ubuntuでカーネルの設定(.config)を変えて再構築（ビルド）する

追記(2021/11/15): clang-13 で Linux 5.15 をコンパイルする話は[こちら](https://qiita.com/kakinaguru_zo/items/3a6bd2684240f9852dd9)。最近はclangでできることはgccではなくclangを用いている。カーネルコンパイルではclangを用いるとLTO, CFI, Shadow Stackなどgccでは選べない設定項目が選べる。

追記(2021/07/30): Intel/AMD系なら `KCFLAGS=-march=native`, それ以外なら `KCFLAGS=-mcpu=native` を付けるとコンパイルした計算機で動作が速くなる （[KCFLAGSの説明](https://www.kernel.org/doc/html/latest/kbuild/kbuild.html#kcflags)）。たとえば `make -j 4 KCFLAGS=-march=native bindeb-pkg` など

* 最近の正しい手順は`make bindeb-pkg` なのにqiita内の記事にはどこにも書いていない
* `CONFIG_SYSTEM_TRUSTED_KEYS=` を空文字列にしないとコンパイル出来ない
* `kernel-package` の `make-kpkg` は最近廃止された
* [Debian 管理者ハンドブック](https://debian-handbook.info/browse/ja-JP/stable/sect.kernel-compilation.html)も古い
* CONFIG_PSI (Pressure Stall Information) をDebianでしたい


という事情でやり方を調べるのに苦労したのでメモします。Debian の公式な手順は https://kernel-team.pages.debian.net/kernel-handbook/ch-common-tasks.html に書いてあります。Secure Bootには以下の手順は対応していません。Pressure Stall Information の説明は

* [PSIをLXCのコンテナで試す: その(2) そもそもの値の定義・CPU Pressureをもう少し測る](https://udzura.hatenablog.jp/entry/2019/02/15/170221) ←良記事でお勧めです
* [https://facebookmicrosites.github.io/psi/docs/overview](https://facebookmicrosites.github.io/psi/docs/overview)

などが参考になります。Linuxカーネルソースの`Documentation`の中の`psi.txt`に、システムの負荷が一定値を超えたらユーザープロセスに通知して処理を始める方法も書いてあります。Ubuntuの場合Disco (19.04)およびそれより新しいものは標準でPSIを使えるようになっていて `/proc/pressure/` にあるファイルから情報を読み取れます。PSIは最近のDebianやUbuntuカーネルではONになっていて `atop` （`top`のエラいやつ）で表示できます。

## 構築環境の準備

`/etc/apt/sources.list` で `deb-src` で始まる行をすべてコメントアウトしていることも多いと思いますが、そうすると `apt-get build-dep` などが動かないので有効にして `sudo apt-get update` して下さい。

1. `sudo apt-get install build-essential libncurses-dev fakeroot dpkg-dev`
2. `sudo apt-get build-dep linux`

## カーネルソースの入手

以下のどちらかをやってください

* ディストリビューションのカーネルソースパッケージを入手する。例えば `sudo apt-get install linux-source`。入手したカーネルソースは `/usr/src` に置かれる
* [https://www.kernel.org](https://www.kernel.org) から最新のソースを入手する

カーネルソースのアーカイブを、一般ユーザーのホームディレクトリなど適切な場所に展開する、例えば `xzcat linux-???.tar.xz | tar xvf -`

## ディストリビューションのカーネル.configの入手と設置
自分で `make nconfig` ですべての項目を適切に設定する場合はこの手順は不要です。

* いま使っているカーネルと同じ（または近い）バージョンを再構築する場合 `/boot` にあるconfigナントカファイルをカーネルソースディレクトリの`.config` という名前にコピーする。
* Debian の最新バージョンを使う場合`experimental` レポジトリから入手する。例えば `sudo apt-get -t experimental install linux-config-5.0` 。.configファイルは `/usr/src` に置かれる。
* Ubuntu の最新バージョンおよび古いバージョンの`.config`は [https://kernel.ubuntu.com/~kernel-ppa/config/](https://kernel.ubuntu.com/~kernel-ppa/config/) から入手できる。

このコンフィグファイルを例えば `linux-5.1.15/.config` という名前でコピーする。上記の２番目と３番目のコンフィグファイルでは`CONFIG_SYSTEM_TRUSTED_KEYS=` が空文字列になっているためコンパイルがエラーで止まるトラブルが発生しない…

## 最低限必要な`.config`への変更

* `CONFIG_SYSTEM_TRUSTED_KEYS` をから文字列にするか自分で用意した `.pem` ファイルに設定しないとエラーでコンパイルができない

## 普通は`n`にして構わない設定項目
* `CONFIG_MODULE_SIG` を `n` にするとモジュール構築時に電子署名しなくなるから時間が短くなる
* `CONFIG_DEBUG_INFO` を `n` にするとデバッグ情報が含まれなくなりファイルサイズとコンパイルに必要なディスク容量が減る

## 筆者の個人的な設定
* `CONFIG_PSI=y`: Pressure Stall Information を使用したいから
* `CONFIG_CPUSETS=n` `CONFIG_PROC_PID_CPUSET=n`: [cgroup v2環境下で`libvirt` 5.0を用いるときにエラーが出る](https://bugzilla.redhat.com/show_bug.cgi?id=1688736) から。Ubuntu Discoでcgroup v2を有効にして`virt-manager`などを使おうとすると operation 'setCpusetMemoryMigrate' not supported と怒られて起動しませんが、`CONFIG_CPUSETS=n` したカーネルなら使えます。この問題は`libvirt`のバージョンが5.2以上なら解決しているため、`Ubuntu Eoan`または`Debian Experimental`から`libvirt-daemon`をインストールすると直ります。

上記の設定をまとめて、カレントディレクトリを `linux-5.1.15` などに移してから

```shell-session
linux-5.1.15$ ./scripts/config  --disable MODULE_SIG  --disable DEBUG_INFO --set-str SYSTEM_TRUSTED_KEYS "" --set-str MODULE_SIG_KEY "" --enable PSI --disable CPUSETS --disable PROC_PID_CPUSET
```

で実行できる。

## `.config` ファイルをコンパイルしたいカーネルバージョンに合わせる
`make oldconfig` すると上記で作った `.config` ファイルには存在しない設定項目をどうするか聞いてくれるので、回答する

## コンパイル
```shell
nice make -j 6 bindeb-pkg
```

`-j` と `LOCALVERSION=` の引数は好きなように変えて下さい。コンピューターの性能に依存しますが数十分かかるので気長にまちます。本記事の末尾にあるように `/proc/pressure/cpu` が100%近くなるまで `-j` の引数を大きくするとCPUの遊び時間が無くなります。

## インストール

NVIDIAのプロプライエタリドライバみたいに[DKMS](https://wiki.archlinux.jp/index.php/Dynamic_Kernel_Module_Support) を使うデバイスドライバを用いているときに`kernel-image`だけインストールすると再起動後に画面が出なくなったりして悲しくなるため、注意する。再起動する前にリモートログイン出来るようにせってしたほうがよい。

上記のコンパイル成功後に `linux-imageナントカ`, `linux-headersナントカ`, `linux-libc-devナントカ` というパッケージができるため、まず`linux-headersナントカ`, `linux-libc-devナントカ`を `sudo dpkg -i` でインストールする。その後に`linux-imageナントカ`をインストールするが、DKMSを用いているときはサードパーティ製モジュールの再コンパイルが行われるからそこでエラーが起きないか注視する。エラーが出ているのに再起動すると悲しいことになる。

## Pressure Stall Information
コンテナを用意してその中で上記の手続きを実施し、[PSIをLXCのコンテナで試す: その(2) そもそもの値の定義・CPU Pressureをもう少し測る](https://udzura.hatenablog.jp/entry/2019/02/15/170221) の記事に従ってコンテナの `io.pressure` と `cpu.pressure` を眺めると、`apt-get build-dep` ではIOが原因で処理遅延が生じ `make bindeb-pkg` では主にCPUが原因で処理遅延が生じていることがよくわかります。また、CPUをフル稼働させるように、注目しているControl Groupの `cpu.pressure` が100%近くになるまでジョブを詰め込む用途にも使えます。

## 参考文献

* [BuildADebianKernelPackage](https://wiki.debian.org/BuildADebianKernelPackage) 良記事。`CONFIG_SYSTEM_TRUSTED_KEYS = ""` しないとコンパイルがエラーで止まることがちゃんと書いてある
* https://kernel-team.pages.debian.net/kernel-handbook/ch-common-tasks.html は Debian の公式な手順書
* [linux kernelのmakeターゲットについてのあれこれ](https://qiita.com/satoru_takeuchi/items/b372303f62b7ca8b128c)　良記事。この記事で勧められるように `make help | less` を読むと新しい知識が増える
* [第526回　Ubuntuで最新のカーネルをお手軽にビルドする方法](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0526) Ubuntuでは `CONFIG_SYSTEM_TRUSTED_KEYS=` の問題は元々生じないからそのことは記事では触れられていないのであった…