---
tage: 自學
---
> 建議直接閱讀[FirstKernelPatch](https://kernelnewbies.org/FirstKernelPatch)
# 怎麼給 Linux Kernel 發 patch?
花了兩天的時間按照[FirstKernelPatch](https://kernelnewbies.org/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](https://kernelnewbies.org/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 筆記](/QY3sSIsbQ4Cq0Dawvn0xbg)
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](http://elixir.free-electrons.com/linux/latest/source/Documentation/process/coding-style.rst),由於太多規則,因此開發者們製作了`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](https://kernelnewbies.org/PatchPhilosophy)以及[CodingStyle](http://elixir.free-electrons.com/linux/latest/source/Documentation/process/coding-style.rst)。
雖然有`checkpatch.pl`,但還是要自己判端是否需要進行改動。另外,請閱讀[CheckpatchTips](https://kernelnewbies.org/CheckpatchTips)以避免提交非必要的改動。
### 清理driver
在`drivers/staging/`中,有許多的driver是不符合[CodingStyle](http://elixir.free-electrons.com/linux/latest/source/Documentation/process/coding-style.rst)的,因此我們的第一個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](https://kernelnewbies.org/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
記錯了,是用這個,但後來在發patch set時maintainer 建議用`git send-mail`
```shell=
mutt -H /tmp/0001-<Whaever your filename is>
```
2. 透過`git send-email`寄出
先在`.gitconfig`的設定中,要再加入以下幾行
```=
[sendemail]
smtpServer = smtp.gmail.com
smtpServerPort = 587
smtpEncryption = tls
smtpUser = example@gmail.com
[credential]
helper = store
```
然後指令
```shell=
git send-email --annotate HEAD^
```
這會接著問你要寄給誰,直接將剛剛找到的維護者名單(包含Email)貼上,接著寄出即可。
### 怎麼修改 Patch
當 Patch 送出後,免不了有需要修改的地方。當被要求修改時,有些小地方要注意。
1. 如果只是要修改一小部分,建議使用 `git commit --amend`
2. Patch 檔需要修改,以最近送出的 Patch 為例
- 將 `[Patch]` 改為 `[Patch v2]` 或者其他版本
- 在 `Signed-off-by` 後面的 `---` 下面添加該版本與前一版本的差異
```
From 264e6aa74304248a393f615bc82c16f778db4d06 Mon Sep 17 00:00:00 2001
From: Matt Jan <zoo868e@gmail.com>
Date: Tue, 14 May 2024 11:57:23 +0800
Subject: [PATCH v2] connector: Fix invalid conversion in cn_proc.h
The implicit conversion from unsigned int to enum
proc_cn_event is invalid, so explicitly cast it
for compilation in a C++ compiler.
/usr/include/linux/cn_proc.h: In function 'proc_cn_event valid_event(proc_cn_event)':
/usr/include/linux/cn_proc.h:72:17: error: invalid conversion from 'unsigned int' to 'proc_cn_event' [-fpermissive]
72 | ev_type &= PROC_EVENT_ALL;
| ^
| |
| unsigned int
Signed-off-by: Matt Jan <zoo868e@gmail.com>
---
change in v2:
fix: remove space after cast
include/uapi/linux/cn_proc.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/include/uapi/linux/cn_proc.h b/include/uapi/linux/cn_proc.h
index f2afb7cc4926..18e3745b86cd 100644
--- a/include/uapi/linux/cn_proc.h
+++ b/include/uapi/linux/cn_proc.h
@@ -69,8 +69,7 @@ struct proc_input {
static inline enum proc_cn_event valid_event(enum proc_cn_event ev_type)
{
- ev_type &= PROC_EVENT_ALL;
- return ev_type;
+ return (enum proc_cn_event)(ev_type & PROC_EVENT_ALL);
}
/*
--
2.25.1
```
3. 寄信的時候可以直接複製 lore.kernel.org 要回覆信件 `Reply instructions` 中的指令
## 後記
我在 2022/12/04 寄出patch,並於 2022/12/05收到回覆說會放到`staging-testing` branch中。
現在`staging-testing`分支中,已經有加上我的[patch](https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/commit/?h=staging-testing&id=bf44039f1ee828c47e1eb83eb315f0fed5a66126)啦~~