A Beginner's Guide to Linux Kernel Developmentを受講した

話題になっていたLinux Foundationの無料のe-Learning、[A Beginner’s Guide to Linux Kernel Development ](https://training.linuxfoundation.org/training/a-beginners-guide-to-linux-kernel-development-lfd103/)を受講したので備忘メモを残しておく。

# 感想

無料でこれだけのe-Learningが受講できるというのは素直にすごい。
感謝感謝です。

Linux Kernelの開発に参加するための方法をわかりやすく丁寧に説明してくれている。
しかも、これならできるかな？と思えるぐらい敷居の低いcontributionのアイディアもたくさん紹介してくれているので、やる気になる。

また、実際にMailing Listにpatchを送るかどうかは別として、Linux Kernelの開発プロセスを知ることができるのはとてもおもしろい。
世界中にちらばっている開発者が、顔をあわせることなくこれだけ大規模な開発を行って、しかも大成功している開発のプロセスというのはそれだけで勉強になる。
Mailing Listを読むときに使える知識もたくさん含まれているし、他のプロジェクトに応用できそうなノウハウもたくさんある。

各章末に用意されている理解度確認テストは、思ったよりたくさん間違えてしまったが、これも勘違いしたまま先に進まなくてすんだのでとても良かった。

私は実際に試しながらメモを取りながら進めたので結構時間がかかったが、
多分読むだけだったら２〜３時間かかるかどうかというところだと思う。

# e-Learning自体について

[こちら](https://training.linuxfoundation.org/training/a-beginners-guide-to-linux-kernel-development-lfd103/)から受講を申し込むと、１年間無料で受講できる。

受講開始時、氏名を日本語で登録したらアカウント作成は成功するが受講ができなかった。
記憶がおぼろげだが、たしかGoogleアカウント連携したら自動的に日本語の氏名が入力されたのでそのまま登録した気がする。
後日、サポートから「ラテン文字以外はまだ対応してないからラテン文字での名前を教えてほしい」とのこと。
丁寧なサポートのおかげでことなきを得たが、これから受講する場合はとりあえずラテン文字にしておいたほうが無難ぽい。

しばらく操作しないと（30分ぐらい？）、セッションが切れる。

アカウントに紐付けて進捗を保存してくれるので、家ではPC、外ではスマホみたいなことも可能。

実際に試す場合は、そこまで依存しないけど、ある程度新しめのUbuntuを想定してる。
Ubuntu 18.04で進めたが、特に困ったことはなかった。

# Ch 2. Linux Kernel Development Process
## 2.4. About the Linux Kernel

新しいmainline kernelは2-3ヶ月に一度リリースされる。
リリースされたmainline kernelはstable kernelとみなされる。
以降はバグフィックスなどの必要最低限のコミットが取り込まれたものが、通常週一回のペースでリリースされる。
Stable kernelは、次のmainline kernelがリリースされるまで、メンテナンスされる。
ただし、stable kernelの中には、特別に長期間メンテナンスされるlongterm kernelがある。
（4.4, 4.9, 4.14, 4.19など）
Longterm kernelは、次のmainline kernelがリリースされても、予め定めたEOL(End Of Life)までメンテナンスされる。

以上のようにkernelのリリースは、機能追加に応じて行うわけではなく、時期に基づいて行われる。
ただし、時期はバグの状況などによって多少前後する。


- 参考
  - [The Linux Kernel Archives - Releases](https://www.kernel.org/category/releases.html)

## 2.5. What Does the Release Cycle Look Like?

Mainline kernelをリリースした直後から、以下の流れで次のリリースに向けて開発が行われる。

- merge window (2週間)
  - susbystem maintainerからLinusへのpullreqがmergeされる
  - merge window完了時に**rc1**がリリース
- bug fix only mode (major bugがなくなるまで)
  - **rc1**リリースの1週間後、**rc2**がリリース
  - **rc2**リリースの1週間後、**rc3**がリリース
  - major bugがなくなるまで繰り返し(だいたいrc7かrc8まで続く)

公式に決まっているわけではないが、stable releaseの一週間前から、次のmerge windownまでの合計３週間をquiet periodと呼ぶ。
この期間は次のリリースに向けた準備期間でメンテナが特に忙しいため、こう呼ばれている。

- 参考
  - [kernel/git/torvalds/linux.git - Linux kernel source tree](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/refs/tags)



## 2.7. Kernel Trees - What Are They?

- The Mainline kernel tree
  - Linus Torvaldsがメンテナ。
  - mainline kernel releaseとRC releaseがリリースされる。
  - [kernel/git/torvalds/linux.git - Linux kernel source tree](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/)

- The Stable tree
  - Greg Kroah-Hartmanがメンテナ。
  - stable releaseがリリースされる。
  - [kernel/git/stable/linux.git - Linux kernel stable tree](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/)

- The linux-next tree
  - Stephen Rothwellがメンテナ。
  - subsystemの変更がすべて取り込まれ、integrationテスト用にリリースされる。
  - [kernel/git/next/linux-next.git - The linux-next integration testing tree](https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/)


- 参考
  - [HOWTO do Linux kernel development — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/howto.html)

## 2.8. Subsystem Maintainers
susbystemごとにメンテナがいて、[MAINTAINERS](https://www.kernel.org/doc/linux/MAINTAINERS)から見つけることができる。
また、だいたいのsubsystemにはメーリングリストがあり、開発はメールベースで行われる。
メーリングリストの一覧は、[Majordomo Lists at VGER.KERNEL.ORG](http://vger.kernel.org/vger-lists.html)と[List archives on lore.kernel.org](https://lore.kernel.org/lists.html)にある。

# Ch 3. Patches
## 3.5. What's in A Patch?

下記パッチを題材に各項目を解説している。

```
$ git format-patch -1 --pretty=fuller 3a38e874d70b
0001-usbip-usbip_host-cleanup-do_rebind-return-path.patch
$ cat 0001-usbip-usbip_host-cleanup-do_rebind-return-path.patch
commit 3a38e874d70b1c80a3e3118be6fc010b558cc050
Author:     Shuah Khan <skhan@linuxfoundation.org>
AuthorDate: Thu May 2 13:47:18 2019 -0600
Commit:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
CommitDate: Tue May 21 08:34:49 2019 +0200

    usbip: usbip_host: cleanup do_rebind() return path
    
    Cleanup do_rebind() return path and use common return path.
    
    Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
 drivers/usb/usbip/stub_main.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c
index bf8a5feb0ee9..2e4bfccd4bfc 100644
--- a/drivers/usb/usbip/stub_main.c
+++ b/drivers/usb/usbip/stub_main.c
@@ -201,7 +201,7 @@ static DRIVER_ATTR_RW(match_busid);
 
 static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
 {
-	int ret;
+	int ret = 0;
 
 	/* device_attach() callers should hold parent lock for USB */
 	if (busid_priv->udev->dev.parent)
@@ -209,11 +209,9 @@ static int do_rebind(char *busid, struct bus_id_priv *busid_priv)
 	ret = device_attach(&busid_priv->udev->dev);
 	if (busid_priv->udev->dev.parent)
 		device_unlock(busid_priv->udev->dev.parent);
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(&busid_priv->udev->dev, "rebind failed\n");
-		return ret;
-	}
-	return 0;
+	return ret;
 }
 
 static void stub_device_rebind(void)
-- 
2.17.1

```

- **Commit header**
  - `:`区切りで、major subsystem: minor area: 変更の要約。
  - メンテナによっては`/`区切りの場合もある。

- **Author**
  - パッチの作成者。

- **AuthorDate**
  - パッチの作成日時。

- **Commit**
  - パッチをリポジトリに取り込んだ人。例の場合はsubsystemのメンテナ。

- **CommitDate**
  - パッチをリポジトリに取り込んだ日付。
  - 例の場合はパッチ作成から19日後に取り込まれている。
  - 取り込まれるまでにどれぐらいかかるかはリリースサイクルに依存して、19日は特に長くはない。

- **Signed-off-by**
  - パッチを作成した人および導入した人。
  - パッチを送るときは、送信元メールアドレスと同じアドレスでSigned-off-byの行を付与する必要がある。
  - Signed-off-byで承認する内容はプロジェクト依存だが、Linux Kernelの場合は、[the Developer's Certificate of Origin](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin)
  - 実名しか使えない。

- **Acked-by**
  - パッチをレビューし承認した人。
  - 例えば、パッチに影響を受けるsubsystemのメンテナが、パッチを作成してもいないし導入にも関わっていない場合、承認した記録を残すために**Acked-by**を使うことがある。
  - パッチ全体に対して承認したとは限らない。

- **Reviewed-by**
  - パッチをレビューし承認した人。
  - **Acked-by**と比較してより厳格で、レビュワーはパッチ全体を確認した上でmainlineに導入することに技術的課題がないと宣言することになる。

- 参考
  - [Submitting patches: the essential guide to getting your code into the kernel — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin)
  - [Git - git-commit Documentation](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt--s)
  - [Git - SubmittingPatches Documentation](https://git-scm.com/docs/SubmittingPatches/2.22.0#sign-off)

## 3.7. Patch Email Subject Line Conventions

パッチを送る際のメールのタイトルのプレフィックスについて。

- **[PATCH]**
  - パッチが添付されていることを示す。

- **[PATCH RFC]** or **[RFC PATCH]**
  - パッチへのコメントがほしいことを示す。
  - RFCはRequest For Commentの略。

- **[PATCH v4]**
  - 同一の目的の修正に対して、4つ目のバージョンのパッチであることを示す。

## 3.8. Patch Version History

パッチに対して指摘をもらい、修正して再度パッチを送る場合のお作法。
パッチの変更履歴を、`---`と`diff`の間に書かなければならない。
この変更履歴は、マージ時に取り除かれる。
また、変更後のパッチは、新しいメールスレッドで投稿されなければならない。

例：[LKML: Shuah Khan: [PATCH v2] selftests: Add kselftest-all and kselftest-install targets](https://lkml.org/lkml/2019/9/26/714)

```
Add kselftest-all target to build tests from the top level
Makefile. This is to simplify kselftest use-cases for CI and
distributions where build and test systems are different.

Current kselftest target builds and runs tests on a development
system which is a developer use-case.

Add kselftest-install target to install tests from the top level
Makefile. This is to simplify kselftest use-cases for CI and
distributions where build and test systems are different.

This change addresses requests from developers and testers to add
support for installing kselftest from the main Makefile.

In addition, make the install directory the same when install is
run using "make kselftest-install" or by running kselftest_install.sh.
Also fix the INSTALL_PATH variable conflict between main Makefile and
selftests Makefile.

Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
---
Changes since v1:
- Collpased two patches that added separate targets to
  build and install into one patch using pattern rule to
  invoke all, install, and clean targets from main Makefile.

 Makefile                                     | 5 ++---
 tools/testing/selftests/Makefile             | 8 ++++++--
 tools/testing/selftests/kselftest_install.sh | 4 ++--
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile
index d456746da347..ec296c60c1af 100644
--- a/Makefile
+++ b/Makefile
@@ -1237,9 +1237,8 @@ PHONY += kselftest
（以下略）
```

# Chapter 4. Working with the Linux Kernel Community
## 4.4. Linux Kernel Contributor Convenant Code of Conduct

- 参考
  - [Contributor Covenant Code of Conduct — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/code-of-conduct.html)
  - [Linux Kernel Contributor Covenant Code of Conduct Interpretation — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/code-of-conduct-interpretation.html)

## 4.5. Linux Enforcement Statement

- 参考
  - [Linux Kernel Enforcement Statement — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/kernel-enforcement-statement.html)

# Ch 5. Configuring Your Development System

## 5.4. Getting Your System Ready

Ubuntuを例にカーネルの開発に必要な環境を整えていく。

```
sudo apt-get install build-essential vim git cscope libncurses-dev libssl-dev bison git-email
```

- 参考
  - [Minimal requirements to compile the Kernel — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/changes.html)
  - [Email clients info for Linux — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/email-clients.html)

## 5.5. Git Email Configuration

`git send-email`を使うための設定。
`.gitignore`に以下の設定をすれば良い。
(なお、smtppassを指定しなければ実行時に確認してくれる)

```
[sendemail]
    smtpserver = smtp.gmail.com
    smtpserverport = 587
    smtpencryption = tls
    smtpuser = <username>
    smtppass = <password>
```

`git send-email`の設定が正しくできていれば、`git format-patch`コマンドで作成したパッチに対して、`git send-email mypatch.patch`とすることでパッチを送付できる。

ただし、例のようにgmailを使うときは、Googleの「マイアカウント」から「安全性の低いアプリを許可する」を有効にしておかないと送信をブロックされるので注意。

- 参考
  - [Git - Gmailでgit send-emailを使用する | git Tutorial](https://riptutorial.com/ja/git/example/16977/gmail%E3%81%A7git-send-email%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)

## 5.6. Email Client Configuration

Communityとメールするときに気をつけるべきこと。

- Top postでなく、**Bottom post**すべし。つまりこれまでのメッセージのあとに新しいメッセージを書く。
- 返信するときは、元メールの中で関係ない箇所は消す。
- HTMLは使わない(Mailing listで自動的に弾かれる)。
- 署名はつけない（プライバシーに関するトラブルを避けるため）。
- パッチは添付しない。
- 基本的に添付ファイルは使わない。ただし、バグ報告のときのkernel logやconfigファイルは例外。



- 参考
  - [Top Posting and Bottom Posting](http://www.idallen.com/topposting.html)
  - [Email clients info for Linux — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/email-clients.html)

# Ch 6. Exploring Linux Kernel Sources

## 6.5. Cloning the Linux Mainline

mainline kernelを取得する。

```shell-session

git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux_mainline
```

- 参考
  - [Linux mainline](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/)


## 6.6. What's in the Root Directory?

[cregit-Linux](https://cregit.linuxsources.org/)というサービスで、
Linux kernelのディレクトリごとの行数・ファイル数及びContributorごとの割合を見ることができる。

- 参考
  - [Release 5.2 · cregit](https://cregit.linuxsources.org/code/5.2/)

## 6.7. Exploring the Sources

kernelの開発では、以下のファイルを日々使う。

- Makefile
- MAINTAINERS
- scripts/get_maintainer.pl
- scripts/checkpatch.pl

## 6.8. Exploring the linux-kselftest Repository

kselftest frameworkのリポジトリを取得する。

```
git clone git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git linux_kselftest
cd linux_kselftest
git checkout next
```

- 参考
  - [kernel/git/shuah/linux-kselftest.git - Kselftest Framework](https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git/)

# Ch 7. Building and Installing Your First Kernel

## 7.4. Cloning the Stable Kernel Git

最新のstable kernelを取得する。

```
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux_stable
cd linux_stable
git branch -a | grep linux-5
    remotes/origin/linux-5.0.y
    remotes/origin/linux-5.1.y
    remotes/origin/linux-5.2.y
    remotes/origin/linux-5.3.y
git checkout linux-5.3.y
```

## 7.5. Copying the Configuration for Current Kernel from /boot

自身の環境のkernel configを、ビルドツリーにコピーする。

```
cd linux_stable
cp /boot/config-$(uname -r) .config
```

## 7.6. Compiling the Kernel

7.5.でコピーした`.config`を基に、最新のstable kernelのconfigurationを行う。
最新のstable kernelまでに追加された新しい機能やドライバについては、どうするか尋ねられる。

```
make oldconfig
```

不要なコンフィグを無効にしたい場合は、下記のコマンドで今loadしているモジュール以外無効にすることができる。

```
make LSMOD=/tmp/my-lsmod localmodconfig
```

コンフィグが完了したら、下記コマンドでkernelをコンパイルする。
`-j`オプションは並列ビルド数。

```
make -j3 all
```

## 7.7. Installing the New Kernel

コンパイルが完了したら、下記コマンドでコンパイルしたkernelをインストールする。
`update-grub`コマンドも実行してくれるので、あとは再起動するだけでコンパイルしたkernelで起動される。

```
sudo make modules_install install
```

再起動前に、比較するため、下記コマンドで現行のkernelのログを保存しておく。
`dmesg`コマンドは`-t`オプションでタイムスタンプなしで出力できる。

```
dmesg -t > dmesg_current
dmesg -t -k > dmesg_kernel
dmesg -t -l emerg > dmesg_current_emerg
dmesg -t -l alert > dmesg_current_alert
dmesg -t -l crit > dmesg_current_crit
dmesg -t -l err > dmesg_current_err
dmesg -t -l warn > dmesg_current_warn
```

一般的に、`emerg`, `alert`, `crit`, `err`レベルのdmesgは出力されているべきではない。


## 7.8. Booting the Kernel

新しいkernelが起動できないかもしれないので、再起動して試す前に、
いつでもgrub menuで今のkernelに戻せるようにしておいたほうがいい。

具体的には、`/etc/default/grub`の`GRUB_TIMEOUT=10`として、`GRUB_TIMEOUT_STYLE=hidden`をコメントアウトする。
その後、変更を反映するために`sudu update-grub`を実行する。

また、Secure Bootが有効になっている場合、自分でコンパイルしたkernelは署名が付与されていないため起動できない。
予めBIOSの設定画面で無効にしておく必要がある。


もしそれでも再起動後うまく動かない場合、初期のブートメッセージをvgaに出力することで原因がわかるかもしれない。
その場合、`GRUB_CMDLINE_LINUX="earlyprintk=vga"`とする。


# Ch 8. Writing Your First Kernel Patch

## 8.5. Kernel Configuration

ドライバのインストールオプションには下記の３つがある。

- ビルドしない。
- kernel(vmlinux)に組み込む。
- loadable kernel moduleとしてビルドして、必要になったら`modprobe`でloadする。


`make listnewconfig`で、`.config`ファイルと比較して新しく追加されたコンフィグの一覧を確認できる。

- 参考
  - [Kconfig make config — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/kbuild/kconfig.html)
  - [Kernel Build System — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/kbuild/index.html)


## 8.7. Adding a Remote

mainline kernelのrelease tagを参照するためにmainline kernelをremoteに追加する。

```
git remote add linux git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
git fetch linux
```

## 8.8. Making Changes to a Driver

`lsmod`でロードされているドライバの中から一つ選択し、ロード時に呼び出される`probe`関数を修正してみる。
今回は`usbhid`をいじってみた。

下記コマンドでgitリポジトリに登録されているMakefileの中から`usbhid`という文字列を検索できる。

```
$ git grep usbhid -- '*Makefile'
drivers/hid/Makefile:obj-$(CONFIG_USB_HID)		+= usbhid/
drivers/hid/Makefile:obj-$(CONFIG_USB_MOUSE)		+= usbhid/
drivers/hid/Makefile:obj-$(CONFIG_USB_KBD)		+= usbhid/
drivers/hid/usbhid/Makefile:usbhid-y	:= hid-core.o
drivers/hid/usbhid/Makefile:usbhid-$(CONFIG_USB_HIDDEV)	+= hiddev.o
drivers/hid/usbhid/Makefile:usbhid-$(CONFIG_HID_PID)	+= hid-pidff.o
drivers/hid/usbhid/Makefile:obj-$(CONFIG_USB_HID)		+= usbhid.o
```

変更が確認できるよう、下記のようにログ出力関数`pr_info`を埋め込む。

```
$ git diff
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index c7bc9db5b192..c0fb6dc769bb 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -1307,6 +1307,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
 	size_t len;
 	int ret;
 
+	pr_info("I changed usbhid driver in the Linux Kernel\n");
 	dbg_hid("HID probe called for ifnum %d\n",
 			intf->altsetting->desc.bInterfaceNumber);
 
```

コンパイル・インストール・再起動後、下記のようにdmesgに出力されていれば、パッチが正しく適用されている。

```
$ dmesg | grep "I changed"
[   10.155766] I changed usbhid driver in the Linux Kernel
[   10.159132] I changed usbhid driver in the Linux Kernel
[   10.160327] I changed usbhid driver in the Linux Kernel
[   10.160966] I changed usbhid driver in the Linux Kernel
```

## 8.9. Practicing Commits

patch作成ワークフローの紹介。

1. 修正を作成し、コンパイルを通す
2. `checkpatch.pl`を実行する
3. `checkpatch.pl`に指摘された内容を修正し、1.に戻る


`checkpatch.pl`は下記コマンドで実行できる。
以下は、tabの代わりにspaceを使ってしまったときの出力。

```
$ git diff > temp; scripts/checkpatch.pl temp
ERROR: code indent should use tabs where possible
#9: FILE: drivers/hid/usbhid/hid-core.c:1310:
+        pr_info("I changed usbhid driver in the Linux Kernel\n");$

WARNING: please, no spaces at the start of a line
#9: FILE: drivers/hid/usbhid/hid-core.c:1310:
+        pr_info("I changed usbhid driver in the Linux Kernel\n");$

total: 1 errors, 1 warnings, 7 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

NOTE: Whitespace errors detected.
      You may wish to use scripts/cleanpatch or scripts/cleanfile

temp has style problems, please review.

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.
```

- 参考
  - [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/)


# Ch 9. Getting Your Patch Ready and Sending It

## 9.4. Sending a Patch for Reveiw

修正したパッチを、誰に送ればいいかは、`get_maintainer.pl`を実行することでわかる。
Mailing listをCCに、それ以外をTOにパッチを送ればいい。

```
$ scripts/get_maintainer.pl drivers/hid/usbhid/hid-core.c
Jiri Kosina <jikos@kernel.org> (maintainer:USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REM...)
Benjamin Tissoires <benjamin.tissoires@redhat.com> (maintainer:USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REM...)
linux-usb@vger.kernel.org (open list:USB HID/HIDBP DRIVERS (USB KEYBOARDS, MICE, REM...)
linux-input@vger.kernel.org (open list:HID CORE LAYER)
linux-kernel@vger.kernel.org (open list)
```

- 参考
  - [Select the recipients for your patch — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/process/submitting-patches.html#select-the-recipients-for-your-patch)


## 9.6. Best Practices for Sending Patches

パッチを送る前に確認すべきポイント。

- パッチを送る前に必ず`script/checkpatch.pl`を実行する。ただし、`checkpatch.pl`に盲目的に従うのではなく、指摘された箇所について、どうするのが一番読みやすいか自分で考えて決断する。
- コンパイルしてテストする。
- **Signed-off-by**タグは最後に書く
- いいパッチであるほど早く取り込まれる。
- 送り先は`script/get_maintainer.pl`で確認する。
- 返事が来るまでに最低1週間は我慢する。merge windowのときなどはもっと時間がかかるかもしれない。
- レビューしてくれた人たちに感謝の意を表す。
- もしコメントの内容が理解できない場合は、遠慮せず質問する。
- 誰かに提案された意見にもとづいてパッチを作っている場合は、**Suggested-by**タグを使って信用を得る。**Tested-by**, **Reported-by**も適切に使うことで信用を得ることができる。
- レビュアーはコードを改善しようとしてくれていることを忘れない。
- Top postで返信せず、回答はinlineで行う。
- Communityの側に、パッチを取り込む義務はない。自分から取り込む理由を提示する。
- 何回もパッチを改修することを覚悟しておく。改修に反対だからと言って、コメントに対して無視してはいけない。反対する理由を技術的な裏付けとともに述べなければならない。
- 一般的に言って、反応があるのは良いことだ。一週間立って返事がなかったら、再度パッチを送るか、紳士的に状況を訪ねてみるといい。
- レビュープロせずのどのタイミングでもコメントが来るかもしれないと覚悟しておこう。
- 一度**linux-next**に取り込まれたら、どのような問題であっても修正する覚悟を持とう。通常はCIで問題が見つけられる。
- パッチが受け入れられたら大体の場合、subsystem treeに取り込まれた旨とmainline kernelに取り込まれるおおよその時期が書かれたメールを受け取る。
- 複数の関連するパッチを送る場合は、`git format-patch -N --cover-letter --thread`とすることでN個のコミットに対応するパッチシリーズとcover letterを作ることができる。
- Cover letterにパッチシリーズのバージョン履歴を入れておくと、レビュアーは変化点を理解しやすい。
- メンテナはパッチを受け入れるとき、そのパッチをメンテナンスする責任を負う。そのためsubsystemごとにパッチが取り込まれる流れは違うし、それぞれのsubsystemの流儀に合わせてコミットログを書くべきだし、それぞれのコーディングスタイルに合わせなかればならない。

## 9.7. Git Post-Commit Hooks

`git`の`post-commit` hookを使うことで、commit時の`checkpatch.pl`の実行を自動化できる。
spell checkも行うために、`codespell`をインストールしておく。

```
sudo apt install codespell
```

`.git/hooks/post-commit`の内容を以下のとおりにすれば実施できる。

```bash
#!/bin/sh
exec git show --format=email HEAD | ./scripts/checkpatch.pl --strict --codespell
```

もしコミット時にerrorかwarningの指摘があったら、修正して`git add`した後`git commit --amend`で再度コミットし直すことができる。


# Ch 10. Kernel and Driver Building, Loading and Dependencies
## 10.4. Compiling a Single Source File: make path/file.o

`make path/file.o`とすることで、単独のソースコードをコンパイルする。

```shell-session
$ make drivers/hid/usbhid/hid-core.o
  CALL    scripts/checksyscalls.sh
  CALL    scripts/atomic/check-atomics.sh
  DESCEND  objtool
  CC [M]  drivers/hid/usbhid/hid-core.o
```

## 10.5. Compiling at the Directory Level: make path

`make path`とすることで、`path`以下をコンパイルする。

```shell-session
$ make drivers/hid/usbhid/
  CALL    scripts/checksyscalls.sh
  CALL    scripts/atomic/check-atomics.sh
  DESCEND  objtool
  CC [M]  drivers/hid/usbhid/hiddev.o
  CC [M]  drivers/hid/usbhid/hid-pidff.o
  LD [M]  drivers/hid/usbhid/usbhid.o
  CC [M]  drivers/hid/usbhid/usbkbd.o
  CC [M]  drivers/hid/usbhid/usbmouse.o
```

## 10.6. Compiling a Module: make M=path

`make M=path`とすることで、`path`以下をコンパイルし、
configが`m`になっているドライバはモジュールの生成まで行う。

```
$ make M=drivers/hid/usbhid/
  CC [M]  drivers/hid/usbhid//hid-core.o
  CC [M]  drivers/hid/usbhid//hiddev.o
  CC [M]  drivers/hid/usbhid//hid-pidff.o
  LD [M]  drivers/hid/usbhid//usbhid.o
  CC [M]  drivers/hid/usbhid//usbkbd.o
  CC [M]  drivers/hid/usbhid//usbmouse.o
  Building modules, stage 2.
  MODPOST 3 modules
  LD [M]  drivers/hid/usbhid//usbhid.ko
  LD [M]  drivers/hid/usbhid//usbkbd.ko
  LD [M]  drivers/hid/usbhid//usbmouse.ko
```

configの依存関係を見るには、`Kconfig`を見れば良い。

```drivers/hid/usbhid/Kconfig
config USB_HID
	tristate "USB HID transport layer"
	default y
	depends on USB && INPUT
	select HID
```

`tristate`は`y`, `n`, `m`の３つの選択肢があることを表す。
つまり、ローダブルカーネルモジュールとしてビルドすることが可能。

`depends on`以降に書かれたconfigが有効でないと、このconfigは有効にできない。
`CONFIG_USB_HID`の場合、`CONFIG_USB`と`CONFIG_INPUT`の両方が有効でないと、有効にできない。

`select`は、このconfigを有効にしたときに自動的になるconfigを示す。
つまり`CONFIG_USB_HID`を有効にすると、`CONFIG_HID`が自動的に有効になる。

`make menuconfig`とすることで、カテゴリごとのconfigの変更をGUIで行うことができる。
`/`を入力することで、検索もできる。



# Ch 11. All About Testing

## 11.5. Automated Build Bots and Continuous Integration Test Rings

[Kernel CI](https://kernelci.org/)では、QEMUや実ハードウェアを使って、たくさんのアーキ・configに対してビルド確認及びテストを実施している。

- 参考
  - [Kernel CI Dashboard](https://kernelci.org/)
  - [Linaro QA](https://qa-reports.linaro.org/)

## 11.7. Basic Testing

新しいkernelで起動させたら、まずは`dmesg -t`の内容に異常がないかを確認する。

そして、典型的なユースケースを動かしてみる。

- 有線・無線でネットワークに接続できるか？
- `ssh`が動作するか？
- `ssh`経由で大きなファイルの`rsync`が動作するか
- `git clone`, `git pull`は動作するか
- ブラウザは動作するか
- emailは読めるか
- `ftp`や`wget`などでファイルのダウンロードはできるか
- 音楽や動画の再生はできるか
- USBデバイスを認識するか

## 11.9. Stress Testing

新しいkernel上でkernelの並列ビルドを行うことは、良い負荷試験・性能試験になる。

```shell-session
time make all -j4
```

## 11.10. Debug Options and Proactive Testing

新しいkernelをtestするときには以下のconfigを有効にしておくのがオススメ。

- `CONFIG_KASAN`: memory leak detection
- `CONFIG_LOCKDEP`
- `CONFIG_PROVE_LOCKING`
- `CONFIG_LOCKUP_DETECTOR`

- 参考
  - [Bug hunting — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/bug-hunting.html)
  - [Bisecting a bug — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/bug-bisect.html)
  - [Dynamic debug — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/admin-guide/dynamic-debug-howto.html)
  - [cregit-Linux · how code gets into the kernel](https://cregit.linuxsources.org/)
  - [Who Made That Change and When: Using Cregit for Debugging - Shuah Khan's Linux Kernel Blogs](http://www.gonehiking.org/ShuahLinuxBlogs/blog/2018/10/18/who-made-that-change-and-when-using-cregit-for-debugging/)

# Ch 12. Tips to Continue Your Kernel Journey

## 12.5. Participating in the Stable Release Process

[Stable release mailing list](http://vger.kernel.org/vger-lists.html#stable)を購読することで、stable kernelに取り込まれる予定のパッチの情報を得ることができる。

そのパッチをあて動作確認を行うことで、Testerとして開発プロセスに参加することができる。

## 12.10. Restart the System and Compare Messages

パッチを適用したkernelが起動したら、まずはdmesgの出力を比較する。
そして、[Kernel Selftests](https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html)を実行し、結果を確認する。
このとき、rootで実行したら再起動してしまうかもしれないので、normal userで実行する。

```
make kselftest
```

- 参考
  - [Linux Kernel Selftests — The Linux Kernel documentation](https://www.kernel.org/doc/html/latest/dev-tools/kselftest.html)

## 12.11. Enhance and Improve Kernel Documentation

documentを整備することでも開発に参加できる。
例えば、以下のコマンドでdocumentをビルドするときのwarning/errorを見つけることができる。

```
make htmldocs > doc_make.log 2>&1
```

## 12.12. Contributing to the Kernel - Getting Started

Linux kernelの開発に参加する取っ掛かりのアイディア。

- 興味のある[Linux Kernel mailing list](http://vger.kernel.org/vger-lists.html)を購読する。
- [Linux Kernel Mailing List Archives](https://lore.kernel.org/lists.html)を読む。
- OFTC IRC networkの#kernelnewbies channelに参加する
- freenodeの#linux-kselftest, #linuxtv, #kernelci, #v4l channelに参加する
- kernel messageのスペルミスを見つける
- 静解析([Sparse](https://www.kernel.org/doc/html/latest/dev-tools/sparse.html))のエラーを修正する。
- ファジングテスト([syzbot](https://syzkaller.appspot.com/upstream))で指摘されている不具合を修正する。
- `.gitignore`がメンテされてなければメンテする。
- `CONFIG_KASAN`やlockのデバッグオプションなどを有効にしてテストし、問題を見つけ、修正する。