--- 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)貼上,接著寄出即可。 ## 後記 我在 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)啦~~