#分享 怎麼給 Linux Kernel 發 patch?
2022年12月6日 21:37 (已編輯)
一直以來都很希望可以參與Linux kernel 的開發,但是一直都沒去實踐。
直到最近在等上工的空檔,終於實際的發第一個patch啦~~
------ 以下正文------
¶ 建議直接閱讀 FirstKernelPatch(註1)
# 怎麼給 Linux Kernel 發 patch?
花了兩天的時間按照FirstKernelPatch的步驟做了一遍後,成功的提交patch,本文希望讓不得其門而入的開發者,可以更容易的加入貢獻Linux Kernel的行列。
建議本文讀者使用過Unix-like作業系統,且熟悉shell操作
## 事前準備
由於我是直接使用 Ubuntu 做測試,因此若使用虛擬機或不同發行版本,所使用的指令以及結果會不盡相同。
- 一部Ubuntu主機
### 安裝開發工具
```shell=
sudo apt-get install vim libncurses5-dev gcc make git exuberant-ctags libssl-dev bison flex libelf-dev bc dwarves zstd git-email esmtp mutt gitk
```
### 下載原始碼
1. 用以下指令下載原始碼
執行下列指令
```shell=
git clone -b staging-testing git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
cd staging
```
2. 設定kernel配置
執行下列指令
```shell=
cp /boot/config-`uname -r`* .config
```
### 工具設定
1. 設定vim為預設編輯器
執行下列指令
```shell=
sudo update-alternatives --config editor
```
選擇`/usr/bin/vim.basic`為預設編輯器
2. 設定Email
由於我用的是Gmail,因此只列出Gmail的設定方式,FirstKernelPatch中有Yahoo的設定方式
設定步驟:設定 -> 轉寄和PIP/IMAP -> IMAP存取 -> 儲存變更
4. esmtp配置
執行下列指令
```shell=
touch ~/.esmtprc
chmod g-rwx ~/.esmtprc
chmod o-rwx ~/.esmtprc
```
編輯`.esmtprc`,新增下列幾行,將Email帳號密碼改成自己的
```=
identity "my.email@gmail.com"
hostname smtp.gmail.com:587
username "my.email@gmail.com"
password "ThisIsNotARealPassWord"
starttls required
```
編輯`.muttrc`,新增下列幾行,將Email帳號改成自己的
```=
set sendmail="/usr/bin/esmtp"
set envelope_from=yes
set from="Your Name <my.email@gmail.com>"
set use_from=yes
set edit_headers=yes
```
4. 測試Email設定
執行下列指令
```shell=
mutt
```
進入`mutt`應用程式,然後按照下列步驟寄信給自己作為測試,#之後為解釋
1. no #不要建立收件夾
2. m #建立新的訊息
3. my.email@gmail.com #輸入自己的信箱
4. test #標題
#這時會跳出`vim`的畫面,內容如下
```=
From: example <example@gmail.com>
To: example@gmail.com
Cc:
Bcc:
Subject: test
Reply-To:
```
5. 在`Reply-To`的下一行打入信件內容,`i`進入編輯模式,`Esc`離開編輯模式,其他操作可參考 Vim 筆記(註2)
6. 離開編輯模式,輸入`:wq`儲存並離開`vim`
7. y #寄出訊息
如果沒有成功收到測試信件,可以用`mutt -d 2`再做一次操作,查看錯誤訊息
5. 設定git
編輯`.gitconfig`,加入下列內容,將名字跟Email改成自己的。
```=
[user]
name = my.name
email = my.email@example.com
[sendmail]
smtpserver = /usr/bin/esmtp
```
須注意該Email要跟前面設定的是同一個,否則不會被接受
¶ The Linux kernel developers will not accept a patch where the "From" email differs from the "Signed-off-by" line, which is what will happen if these two emails do not match.
### 更新kernel到最新板
由於kernel時常在更新,若你的版本不是最新版,patch有可能會被拒絕
```shell=
git fetch origin
```
在`fetch`之後,觀察以下指令之輸出,可以發現當前的檔案並沒有任何的修改
```shell=
git log
```
加上特定的branch name即可看到變化
```shell=
git log origin/staging-testing
```
由於我們主要是針對最新板的程式碼做改動,因此要`rebase`更新,其中如果有發生衝突,要再修改你的commit
```shell=
git rebase origin/staging-testing
```
### 修改Driver
透過`lsmod`查看當前電腦載入的驅動程式,從中選出任意的驅動程式,以下用驅動程式`ee1004`為例
```shell=
git grep ee1004 -- '*Makefile' # 找出ee1004驅動程式原始碼,以下為輸出
# drivers/misc/eeprom/Makefile:obj-$(CONFIG_EEPROM_EE1004) += ee1004.o
vim drivers/misc/eeprom/ee1004.c
# 在該檔案的ee1004_probe() function中
# 加入 printk(KERN_DEBUG "I can modify the Linux kernel!\n");
```
### 編譯kernel
```shell=
make # 單核心編譯
make -jX # 多核心編譯,X = 核心數量
```
### 安裝改動
```shell=
sudo make modules_install install
```
### 測試改動
在完成上述步驟之後,需要重新啟動,查看改動是否成功。
重起之後,用以下指令檢查是否有 "I can modify the Linux kernel!"
```shell=
dmesg | grep "I can modify the Linux kernel!"
```
如果有的話代表你成功編譯並啟動了kernel。
若未成功,請到 IRC 的 #kernel-outreachy 尋求幫助
### 恢復改動
到目前為止只是簡單的測試,你並不會提交這個改動,因此你可以透過下列指令恢復改動
```shell=
git reset --hard HEAD
```
## 開始你的第一個patch
### 自動檢查 git commit
首先,由於kernel有很多的協作者,因此制定了很嚴格的coding style(註3),由於太多規則,因此開發者們製作了`checkpatch.pl`來自動檢查,你無須開啟每個檔案用人工的上檢查是否符合規範,僅須透過該工具找出不符合規範的程式碼做修改。
其次,除了程式碼的撰寫風格有嚴謹的規範以外,commit也同樣有撰寫風格的規範,也同樣有檢查工具,我們要修改`.git/hooks/post-commit`的內容為
```=
#!/bin/sh
exec git show --format=email HEAD | ./scripts/checkpatch.pl --strict --codespell
```
透過下列指令啟用
```shell=
apt-get install codespell python-ply python-git
chmod a+x .git/hooks/post-commit
```
設定完成後,未來`git`會自動檢查你所寫的commit,若有任何的錯誤或警告是你所新增的,可以透過下列指令對commit做修改
```shell=
git commit --amend
```
### 測試自動檢查是否成功運作
使用指令,直接對最新的commit做改動,加入多餘的空行
```shell=
git commit --amend
```
理應偵測到最新的改動,並且發出警示,若沒有發出警示,請上 IRC 尋求幫助
### 了解patch
在你建立自己的patch之前,你必須先了解如何建立一個好的patch,這可以讓你的patch更容易被維護者接受。
請閱讀PatchPhilosophy(註4)以及CodingStyle。
雖然有`checkpatch.pl`,但還是要自己判端是否需要進行改動。另外,請閱讀CheckpatchTips(註5)以避免提交非必要的改動。
### 清理driver
在`drivers/staging/`中,有許多的driver是不符合CodingStyle的,因此我們的第一個patch可以很簡單的從這裡開始。
另外,有些驅動程式還有一些尚未實做完成的功能,可以查找`TODO`來知道有哪些功能需要您的貢獻
```shell=
find drivers/staging -name TODO
```
我們可以透過下列指令找出是否有檔案存在coding style的問題,我用`vme_user`作為範例
```shell=
perl scripts/checkpatch.pl -f drivers/staging/vme_user/* | less
```
選定其中的任一警告作為你的第一個patch做修正。未來你可以一次修改多個警告,但是建議遵從PatchPhilosophy的指示發patch,以免被拒絕。
最後,請重新編譯以及載入驅動程式
```shell=
make -j2 && sudo make modules_install
sudo modprobe -r <module_name>
sudo modprobe <module_name>
```
### commit 你的改動
1. 查看你的改動
```shell=
git status
git diff
```
2. 添加你的改動
```shell=
git add # 一次加入所有改動過得檔案
git add <file> # 加入檔案
```
這時候你再執行`git diff`時,就不會看到輸出,因為diff會輸出 unstaged changes,但是你`add`之後,那些改動就是staged changes了,可以使用下列指令查看staged changes
```shell=
git diff --cached
```
3. 回復你的改動
```shell=
git reset <file>
```
4. commit改動
使用以下指令編寫commit,`-s`代表添加 `Signed-off-by`到patch的底部,`-v`代表在patch中放入你改動的部份
```shell=
git commit -s -v
```
commit 的標題必須以`staging:`開頭,建議透過`git log --oneline`查看前人的撰寫方式。
commit 的標題與內容之間應有一行的空行。
5. 檢視你的commit
```shell=
git show HEAD
```
### 提交你的patch
1. 找到你的patch要提交給誰。
每一個driver都有不同的維護者,而你的patch就是要提交給維護該driver的維護者。同樣的,可以透過工具查找出該driver的維護者有哪些。
```shell=
git show HEAD | perl scripts/get_maintainer.pl --separator , --nokeywords --nogit --nogit-fallback --norolestats -f drivers/staging/
# 或者,直接指定檔名,找出維護者
perl scripts/get_maintainer.pl --separator , --nokeywords --nogit --nogit-fallback --norolestats -f drivers/staging/vme_user
# 輸出如下
# Martyn Welch <martyn@welchs.me.uk>,Manohar Vanga <manohar.vanga@gmail.com>,Greg Kroah-Hartman <gregkh@linuxfoundation.org>,linux-kernel@vger.kernel.org,linux-staging@lists.linux.dev
```
2. 使用`git format-patch`建立patch
```shell=
git format-patch -o /tmp/ HEAD^
```
3. 寄出patch
1. 透過`mutt`寄出你的patch
```shell=
mutt -H /tmp/0001-<Whaever your filename is>
```
2. 透過`git send-email`寄出(我是用這個)
```shell=
git send-email --annotate HEAD^
```
這會接著問你要寄給誰,直接將剛剛找到的維護者名單(包含Email)貼上,接著寄出即可。
## 後記
我在 2022/12/04 寄出patch,並於 2022/12/05收到回覆說會放到`staging-testing` branch中。
現在`staging-testing`分支中,已經有加上我的patch啦~~
註1 註2 註3 註4 註5
內文主要提供給想發patch的開發者參考,如果任何地方有誤還請大神們指正!
附上 Hackmd好讀版