內核診斷(二)-- patch 和diff


  1. patch文件結構
  2. 生成patch文件 --diff命令
  3. patch 使用 -- patch命令
    3.1 打path
    3.1撤銷patch
  4. 使用舉例
    4.1 基本命令使用
    4.2 內核打補丁

1. patch文件的結構

補丁頭

補丁頭是分別由---/+++開頭的兩行,用來表示要打補丁的文件。
一個補丁文件中的多個補丁
一個補丁文件中可能包含以---/+++開頭的很多節,每一節用來打一個補丁。所以在一個補丁文件中可以包含好多個補丁。

塊是補丁中要修改的地方。它通常由一部分不用修改的東西開始和結束。他們只是用來表示要修改的位置。
他們通常以@@開始,結束於另一個塊的開始或者一個新 的補丁頭。
塊的縮進
塊會縮進一列,而這一列是用來表示這一行是要增加還是要刪除的。
塊的第一列
+號表示這一行是要加上的。
-號表示這一行是要刪除的。
沒有加號也沒有減號表示這里只是引用的而不需要修改。

diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index f5d7f4134524..26a2198c59b3 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -220,9 +220,6 @@  KBUILD_CFLAGS += -fno-asynchronous-unwind-tables

 # Avoid indirect branches in kernel to deal with Spectre
 ifdef CONFIG_RETPOLINE
-ifeq ($(RETPOLINE_CFLAGS),)
-  $(error You are building kernel with non-retpoline compiler, please update your compiler.)
-endif
   KBUILD_CFLAGS += $(RETPOLINE_CFLAGS)
 endif

2. 生成patch文件 -- diff命令

diff命令比較兩個文件的不同,然后記錄下來,也就是所謂的diff補丁。
語法格式:

diff 【選項】 源文件(夾) 目的文件(夾)
diff -Naur 舊的目錄 新的目錄 > patch文件
diff -Naur 舊的文件 新的文件 > patch文件
給源文件(夾)打個補丁,使之變成目的文件(夾),術語也就是“升級”。

下面介紹三個最為常用選項:
-r 是一個遞歸選項,設置了這個選項,diff會將兩個不同版本源代碼目錄中的所有對應文件全部都進行一次比較,包括子目錄文件。
-N 選項確保補丁文件將正確地處理已經創建或刪除文件的情況。
-u 選項以統一格式創建補丁文件,這種格式比缺省格式更緊湊些。
diff 對目錄有一些限制,需要保持目錄的一致性。
在創建patch的時候文件夾的層數應當是一樣的,比如
代碼:
--- old/modules/pcitableMon Sep 27 11:03:56 1999
+++ new/modules/pcitableTue Dec 19 20:05:41 2000
這樣是可以的。
而代碼:
--- old/try1/other/modules/pcitableMon Sep 27 11:03:56 1999
+++ new/modules/pcitableTue Dec 19 20:05:41 2000
這樣做可能會有一些問題。

3.patch使用 -- patch命令

patch命令,利用diff制作的補丁來實現源文件(夾)和目的文件(夾)的轉換。這樣說就意味着你可以有源文件(夾)――>目的文件(夾),
也可以目的文件(夾)――>源文件(夾)。
對於一個patch文件,有兩種常用使用方法:

cat new-patch | patch -p0
patch -p0 < new-patch
patch -R -p0 < new-patch
    -p0 選項要從當前目錄查找目的文件(夾)
    -p1 選項要忽略掉第一層目錄,從當前目錄開始查找。
    -E 選項說明如果發現了空文件,那么就刪除它
    -R 選項說明在補丁文件中的“新”文件和“舊”文件現在要調換過來了(實際上就是給新版本打補丁,讓它變成老版本)

patch命令里面的層數(-p0?-p1?)
參數-p來指定從第幾層開始比較。比如有一個patch文件的補丁頭是這樣的:

代碼:
--- old/modules/pcitableMon Sep 27 11:03:56 1999
+++ new/modules/pcitableTue Dec 19 20:05:41 2000

如果使用參數-p0,就表示從當前目錄,找一個叫作new的目錄,在它下面找一個叫modules的目錄,再在它下面找一個叫 pcitableMon的目錄。
如果使用參數-p1,就表示忽略第一層,從當前目錄找一個叫modules的目錄,在它下面找一個叫modules的目錄。這樣會忽略掉補丁頭提到的 new目錄。
依此類推。

4. 使用例子

4.1 diff命令生成patch
#diff -aurN a/c a/b
diff -aurN a/c/c/a.c a/b/c/a.c
##diff命令會在補丁文件中記錄這兩個文件的首次創建時間
--- a/c/c/a.c	2019-02-24 10:59:30.351334765 +0800
+++ a/b/c/a.c	2019-02-24 10:52:19.139836763 +0800
@@ -10,5 +10,6 @@
 #include<string.h>
 #include "head.h"
 int main(){
+    printf("hello world\r\n");
     return 0;
 }
diff -aurN a/c/c/head.h a/b/c/head.h
--- a/c/c/head.h	2019-02-24 10:59:30.355336764 +0800
+++ a/b/c/head.h	2019-02-24 10:52:32.942734763 +0800
@@ -7,5 +7,6 @@
  ************************************************************************/
 #ifndef HEADER_H
 #define HEADER_H
+extern void test();
 #endif
4.2 patch使用

打patch

lin@lin:~/mytest$ patch -p0 < 123.patch
patching file a/c/c/a.c
patching file a/c/c/head.h

查看文件

lin@lin:~/mytest$ cat a/c/c/a.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "head.h"
int main(){
    printf("hello world\r\n");
    return 0;
}
lin@lin:~/mytest$ cat a/c/c/head.h
#ifndef HEADER_H
#define HEADER_H
extern void test();
#endif

撤銷patch

lin@lin:~/mytest$ patch -R -p0 < 123.patch
patching file a/c/c/a.c
patching file a/c/c/head.h

查看文件

lin@lin:~/mytest$ cat a/c/c/head.h
#ifndef HEADER_H
#define HEADER_H
#endif

lin@lin:~/mytest$ cat a/c/c/a.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "head.h"
int main(){
    return 0;
}
4.3  內核打patch

內核不同版本介紹:
(一)Linux內核版本類型及patch簡介:
1)基礎版本

2.6.x為基礎版本,patch位置:
http://www.kernel.org/pub/linux/kernel/v2.6/

2)修正版本

2.6.x.y為2.6.x基礎版本之上派生出來的修正版本,稱為-stable內核版本,patch位置:
http://www.kernel.org/pub/linux/kernel/v2.6/

3)發布版本

2.6.x.rcN(Release Candidate)內核,是在2.6.(x-1)之上派生出來的之后版本的侯選版本;此種內核
不穩定,發布的時候表示可以用來測試了;
例如對2.6.21加了新功能后派生出2.6.22-rc1,patch位置:
http://www.kernel.org/pub/linux/kernel/v2.6/testing/

4)git版本

git內核是每日內核樹的快照,此類型比rc內核更不穩定,從基礎版本或rc版本派生出來;
例如2.6.26-git1,2.6.26-rc9-git2,patch位置:
http://www.kernel.org/pub/linux/kernel/v2.6/snapshots/

5)mm版本

mm內核是專門針對內核的mm模塊維護的版本,類似於git版本從基礎版本或rc版本派生出來;
例如2.6.21-mm2, 2.6.21-rc2-mm1,patch位置:
http://www.kernel.org/pub/linux/kernel/people/akpm/patches/2.6/

不同類型內核的patch名稱在前面加上“patch-”(mm內核除外,直接用的版本號),例如:patch-2.6.21, patch-2.6.21.7, patch-2.6.26-git1, patch-2.6.26-rc9-git2, 2.6.21-mm2, 2.6.21-rc2-mm1

(二) 內核補丁類型

  1. 增量補丁

    同一類型的版本的補丁是用本版本對相鄰的前一個版本制作的。
    例如,patch-2.6.21是對2.6.20做的補丁,patch-2.6.22是對2.6.21做的補丁,這就是增量補丁。
    2.6.x基礎版本內核,采用的是增量補丁。

  2. 非增量補丁

    也增量補丁相反,是基本某一固定版本制作的補丁,而非相鄰的前一個版本。
    例如,patch-2.6.21.3是2.6.21.3版本相對於2.6.21基礎版本做的補丁,patch-2.6.21.4是2.6.21.4版本相對於2.6.21基礎版本做的補丁,
    也就是說2.6.21.4與2.6.21.3之前沒有補丁可用。
    rc內核,git內核和mm內核都是非增量補丁,都是相對於當前基礎版本或rc版本制作出來的補丁。

另外,對於rc內核,git內核,相應的patch目錄下面有inc目錄中,包含有增量補丁。

(三)內核版本升級

  1. 同版本升級內核版本

    現有基礎內核版本2.6.21,想轉成2.6.21.7內核stable版本,應該怎么辦?

    (a) 去內核源碼目錄下載patch-2.6.21.7;

    (b) Linux shell下面,cd到2.6.21內核源文件根目錄(linux-2.6.21),

    將patch-2.6.21.7也放在本目錄(命令執行的當前止錄),執行patch命令:
patch -p1 < patch-2.6.21.7
(p1的意思是忽略patch文件(即diff文件)內容中的第一個路徑)

c) 打完補丁后,即變成了2.6.21.7的內核了,如果想回退至2.6.21基礎版本,執行如下命令即可:

patch -R -p1 < patch-2.6.21.7
(-R的參數意思表示回退這個patch)

2.不同版本內核升級
現有基礎內核版本2.6.21,想轉成2.6.23.1內核stable版本,應該怎么辦?

a) 同1中下載patch-2.6.22, patch-2.6.23, patch-2.6.23.1文件,並設置執行路徑和環境;

b) 多次打補丁

patch -p1 < patch-2.6.22 變成了2.6.22
patch -p1 < patch-2.6.23 變成了2.6.23
patch -p1 < patch-2.6.23.1 變成了2.6.23.1

c) 回退操作

patch -R -p1 < patch-2.6.23.1 變成了2.6.23
patch -R -p1 < patch-2.6.23 變成了2.6.22
patch -R -p1 < patch-2.6.22 變成了2.6.21

3.不同內核版本升級

現有基礎內核版本2.6.21-git2,想轉成2.6.22-rc1-mm2內核stable版本,應該怎么辦?

a) 同1中下載patch-2.6.21-git2, patch-2.6.22-rc1, 2.6.22-rc1-mm2文件,

並設置執行路徑和環境;

b)打補丁

patch -R -p1 < patch-2.6.21-git2 變成了2.6.21
patch -p1 < patch-2.6.22-rc1 變成了2.6.22-rc1
patch -p1 < 2.6.22-rc1-mm2 變成了2.6.22-rc1-mm2

c) 回退操作

patch -R -p1 < 2.6.22-rc1-mm2 變成了2.6.22-rc1
patch -R -p1 < patch-2.6.22-rc1 變成了2.6.21
patch -p1 < patch-2.6.21-git2 變成了2.6.21-git2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM