Linux 内核社区靠邮件列表议事。但新手第一次打开 lore.kernel.org,往往被满屏的 Re:、[PATCH v3 2/7]、Signed-off-by 吓到。其实一封正式邮件的结构非常固定,看懂之后,阅读门槛会陡降。

📧 邮件头部:谁在跟谁说话

/ section

邮件头部(Header)是邮件的「身份证」,包含路由、身份、主题等元信息。Linux 社区常用的字段有这些:

From 发件人,通常是作者的真实姓名和邮箱。
To 主要收件人。补丁邮件一般发给对应子系统的邮件列表。
Cc 抄送对象。常包含维护者(Maintainer)、相关开发者、以及邮件列表本身。
Subject 主题行。补丁邮件会带 [PATCH] 标签和版本/序号信息。
Date 发送时间。跨时区协作时用来判断讨论先后。
Message-Id 邮件唯一标识符。后续所有回复都靠它串成线程。
In-Reply-To / References 回复指向。In-Reply-To 指父邮件的 Message-Id,References 记录整条线程链。

下面是一封完整补丁邮件的头部示例:

text
From: Alice Chen <alice@example.com>
To: linux-media@vger.kernel.org
Cc: Hans Verkuil <hverkuil@xs4all.nl>,
    Mauro Carvalho Chehab <mchehab@kernel.org>,
    linux-kernel@vger.kernel.org
Subject: [PATCH v2 3/5] media: dvb: fix race condition in streaming start
Date: Sat, 19 Sep 2026 10:00:00 +0800
Message-Id: <20260919020000.1234-1-alice@example.com>
In-Reply-To: <20260918010000.5678-1-alice@example.com>
References: <20260918010000.5678-1-alice@example.com>

对照上面这封邮件,每个字段的含义就清晰了。

🔖 Subject:密码一样的主题行

/ column

Subject 是新手最容易懵的地方。因为它不只是标题,还承载了大量结构化信息。

text
Subject: [PATCH v2 3/5] media: dvb: fix race condition in streaming start

拆解一下:

[PATCH] 这是一个补丁邮件。
v2 第 2 版。每根据评审修改一次,版本号递增,如 v3、v4。
3/5 这是 5 封补丁邮件中的第 3 封。0/5 通常是 cover letter(封面信)。
media: dvb: fix race condition... 补丁标题。前缀 media: dvb: 是子系统路径,帮助维护者快速定位。

其他常见标签也有固定含义:

[RFC] Request for Comments,征求意见,代码不一定 ready。例如:[RFC] drm: introduce new plane blending API。
[RESEND] 重发。补丁没收到反馈,作者重新投递。例如:[RESEND v2] mm: fix page reclaim stall。
[GIT PULL] 拉取请求。子系统维护者请求 Linus 拉取一个分支。例如:[GIT PULL] media fixes for v6.15-rc1。
[PATCH 0/N] 封面信(cover letter),解释整个补丁系列要解决什么问题。

如果是回复,Subject 前面会加 Re:;如果是转发,会加 Fw:。

text
Subject: Re: [PATCH v2 3/5] media: dvb: fix race condition in streaming start

✍️ 正文与 Signed-off-by

/ column

正文是邮件的沟通主体。补丁邮件的正文通常分三段:

问题背景 说明当前代码有什么问题、什么场景会触发。
解决方案 说明怎么改的、为什么选择这种方式。
测试或影响 说明是否测试过、会影响哪些平台或驱动。

一个典型的正文示例:

text
When the frontend is started concurrently with a tuning request,
the state lock is not held long enough, leading to a use-after-free
in dvb_frontend_stop().

Hold fe->lock across the entire start sequence and move the state
check before any resource is allocated.

Tested on a USB DVB-T2 stick with dvb-usb-rtl28xxu.

Signed-off-by: Alice Chen <alice@example.com>

正文末尾通常有一行或多行 Signed-off-by:

text
Signed-off-by: Alice Chen <alice@example.com>

这行不是签名装饰,而是 开发者原创声明(DCO)。它表示:这段代码是我写的,或者我有权以开源许可证提交它。没有 Signed-off-by 的补丁,维护者通常不会合入。

🧩 补丁邮件的特殊结构

/ column

补丁邮件的正文之后,会跟着一段 --- 分隔线和 diff 内容。

diff
---
 drivers/media/dvb-core/dvb_frontend.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 1a2b3c4..5d6e7f8 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -1456,7 +1456,8 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
 	mutex_lock(&fe->lock);
 	if (fe->state != DVB_FE_IDLE) {
 		mutex_unlock(&fe->lock);
-		return -EBUSY;
+		ret = -EBUSY;
+		goto err;
 	}
 	fe->state = DVB_FE_STARTING;
 	mutex_unlock(&fe->lock);

--- 上面是变更统计(diffstat),下面是具体的代码差异。红色行带 - 是删除,绿色行带 + 是新增。看 diff 时,重点看上下文是否完整、逻辑是否自洽。

🧵 回复与线程

/ column

社区讨论不是单封邮件,而是一棵树。同一个补丁可能被多个人从不同角度回复,作者也会根据评审意见重发 v2、v3。树能立起来,靠的是三个字段:

Message-Id 每封邮件出生时的唯一身份证号,形如 <20260919020000.1234-1-alice@example.com>。
In-Reply-To 只填一封:你直接回复的是哪封邮件,就写它的 Message-Id。
References 从根邮件到父邮件的所有 Message-Id,按顺序列出,用来还原整条路径。

References 的推导规则只有一条:发回复时,References = 父邮件的 References + 父邮件的 Message-Id。每一层都继承上一层,链路因此完整。

下面用一组具体消息 ID 走一遍。场景:Alice 在 9 月 18 日发了 [PATCH 0/2] 封面信和两封补丁,Hans 评审了补丁 1/2,Mauro 评审了补丁 2/2,Alice 据此在 9 月 19 日重发 v2。线程树如下(尖括号里就是 Message-Id):

text
<20260918000000.1000-1-alice@example.com>
  [PATCH 0/2] media: dvb: fix streaming race
  ├─ <20260918000001.1000-2-alice@example.com>
  │    [PATCH 1/2] media: dvb: hold fe->lock in start
  │    └─ <20260918120000.2000-1-hans@xs4all.nl>
  │         Re: [PATCH 1/2] media: dvb: hold fe->lock in start
  └─ <20260918000002.1000-3-alice@example.com>
       [PATCH 2/2] media: dvb: check state before alloc
       └─ <20260918150000.3000-1-mauro@kernel.org>
            Re: [PATCH 2/2] media: dvb: check state before alloc
            └─ <20260919020000.4000-1-alice@example.com>
                 [PATCH v2 0/2] media: dvb: fix streaming race
                 ├─ <20260919020001.4000-2-alice@example.com>
                 │    [PATCH v2 1/2] media: dvb: hold fe->lock in start
                 └─ <20260919020002.4000-3-alice@example.com>
                      [PATCH v2 2/2] media: dvb: check state before alloc

把树上的每条边翻译成真实头部字段:

text
# 1) Alice 的 [PATCH 1/2],父节点是封面信
Message-Id: <20260918000001.1000-2-alice@example.com>
In-Reply-To: <20260918000000.1000-1-alice@example.com>
References: <20260918000000.1000-1-alice@example.com>

# 2) Hans 评审补丁 1/2:In-Reply-To 指向补丁,不是封面信
Message-Id: <20260918120000.2000-1-hans@xs4all.nl>
In-Reply-To: <20260918000001.1000-2-alice@example.com>
References: <20260918000000.1000-1-alice@example.com>
            <20260918000001.1000-2-alice@example.com>

# 3) Mauro 评审补丁 2/2
Message-Id: <20260918150000.3000-1-mauro@kernel.org>
In-Reply-To: <20260918000002.1000-3-alice@example.com>
References: <20260918000000.1000-1-alice@example.com>
            <20260918000002.1000-3-alice@example.com>

# 4) Alice 的 v2 封面信:In-Reply-To 指向最后一轮评审,不是自己的 v1 封面信
Message-Id: <20260919020000.4000-1-alice@example.com>
In-Reply-To: <20260918150000.3000-1-mauro@kernel.org>
References: <20260918000000.1000-1-alice@example.com>
            <20260918000002.1000-3-alice@example.com>
            <20260918150000.3000-1-mauro@kernel.org>

# 5) v2 的第一封补丁:References 重新从 v2 封面信起算
Message-Id: <20260919020001.4000-2-alice@example.com>
In-Reply-To: <20260919020000.4000-1-alice@example.com>
References: <20260919020000.4000-1-alice@example.com>

对照这五段头部,几个新手最容易踩的点就清楚了:

In-Reply-To 只指向直接父节点 Hans 评的是补丁 1/2(第 2 段),所以 In-Reply-To 是补丁自己的 ID,而不是封面信的。写成封面信,评审就会挂错分支。
References 是累加的 父邮件的 References 原样保留,末尾再补上父邮件的 Message-Id。第 2、3 段都比第 1 段多出一项,就是这个规则。
v2 要回复到最后一轮评审 第 4 段的 In-Reply-To 指向 Mauro 的评审,而不是 Alice 自己的 v1 封面信。这样读者能从评审意见直接看到「作者已经改了」。
新一轮系列重新起算 第 5 段的 References 只有 v2 封面信一项——补丁属于新一轮系列,链路从本轮封面信重新开始,不再背着 v1 的历史。

lore.kernel.org 和邮件客户端就是靠这些 ID 把讨论折叠成可展开的树:点开一个评审节点,能一路向上追到它评论的是哪一版补丁,再横向跳到作者有没有发 v2,不必一封一封翻。

回复时,客户端还会在正文顶部用 > 缩进引用原邮件,方便跨时区、异步阅读时不用翻历史就看得到上下文:

text
> On Sat, Sep 19, 2026 at 10:00:00 +0800, Alice Chen wrote:
> > This patch holds fe->lock across the start sequence.
>
> Looks good, but can we also add a comment explaining why?

维护者回复里常见的黑话:

LGTM Looks Good To Me,表示认可。
Acked-by 某维护者审阅并同意,通常会加在补丁末尾。例如:Acked-by: Hans Verkuil
Reviewed-by 比 Acked-by 更正式的代码审查通过标记。例如:Reviewed-by: Mauro Carvalho Chehab
Queued 补丁已加入维护者的本地队列,很快会进入主线。
v2 / v3 / vN 第 N 版补丁。每一轮评审修改后,作者会重发整个系列并递增版本号。

📌 新手建议

/ column
先看,再写 订阅一个子系统列表,默默观察几周,熟悉语气和格式后再参与。
从小补丁开始 第一封邮件不必是大改动,文档拼写错误、格式清理都是好的开始。
保持礼貌具体 技术讨论对事不对人,指出问题时尽量给出具体行号或建议。

看懂邮件结构,是进入 Linux 开源世界的第一步。

Linux 内核玩家 · kernelplayer.cn