code:
.. include:: ../disclaimer-zh_CN.rst

:Original: Documentation/process/coding-style.rst

.. _cn_codingstyle:

:译者:
 - 张乐 Zhang Le <r0bertz@gentoo.org>
 - Andy Deng <theandy.deng@gmail.com>
 - 吴想成 <bobwxc@email.cn>

:校译:
 - 王聪 Wang Cong <xiyou.wangcong@gmail.com>
 - wheelz <kernel.zeng@gmail.com>
 - 管旭东 Xudong Guan <xudong.guan@gmail.com>
 - Li Zefan <lizf@cn.fujitsu.com>
 - Wang Chen <wangchen@cn.fujitsu.com>

Linux 内核代码风格
==================

这是一个简短的文档，描述了 linux 内核的首选代码风格。代码风格是因人而异的，
而且我不愿意把自己的观点强加给任何人，但这就像我去做任何事情都必须遵循的原则
那样，我也希望在绝大多数事上保持这种的态度。请 (在写代码时) 至少考虑一下这里
的代码风格。

首先，我建议你打印一份 GNU 代码规范，然后不要读。烧了它，这是一个具有重大象征
性意义的动作。

不管怎样，现在我们开始：

1) 缩进
-------

制表符是 8 个字符，所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至
2！) 字符深，这几乎相当于尝试将圆周率的值定义为 3。

理由：缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的
屏幕连续看了 20 小时之后，你将会发现大一点的缩进会使你更容易分辨缩进。

现在，有些人会抱怨 8 个字符的缩进会使代码向右边移动的太远，在 80 个字符的终端
屏幕上就很难读这样的代码。这个问题的答案是，如果你需要 3 级以上的缩进，不管用
何种方式你的代码已经有问题了，应该修正你的程序。

简而言之，8 个字符的缩进可以让代码更容易阅读，还有一个好处是当你的函数嵌套太
深的时候可以给你警告。留心这个警告。

在 switch 语句中消除多级缩进的首选的方式是让 ``switch`` 和从属于它的 ``case``
标签对齐于同一列，而不要 ``两次缩进`` ``case`` 标签。比如：

.. code-block:: c

	switch (suffix) {
	case 'G':
	case 'g':
		mem <<= 30;
		break;
	case 'M':
	case 'm':
		mem <<= 20;
		break;
	case 'K':
	case 'k':
		mem <<= 10;
		fallthrough;
	default:
		break;
	}

不要把多个语句放在一行里，除非你有什么东西要隐藏：

.. code-block:: c

	if (condition) do_this;
	  do_something_everytime;

不要使用逗号来避免使用大括号：

.. code-block:: c

	if (condition)
		do_this(), do_that();

使用大括号包裹多语句：

.. code-block:: c

	if (condition) {
		do_this();
		do_that();
	}

也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
的表达式。

除了注释、文档和 Kconfig 之外，不要使用空格来缩进，前面的例子是例外，是有意为
之。

选用一个好的编辑器，不要在行尾留空格。

2) 把长的行和字符串打散
-----------------------

代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。

每一行的长度的限制是 80 列，我们强烈建议您遵守这个惯例。

长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性，并且不
会隐藏信息。

子片段要明显短于母片段，并明显靠右。一种非常常用的样式是将子体与函数左括号对齐。

这同样适用于有着很长参数列表的函数头。

然而，绝对不要打散对用户可见的字符串，例如 printk 信息，因为这样就
很难对它们 grep。

3) 大括号和空格的放置
---------------------

C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同，选择或弃用某种放
置策略并没有多少技术上的原因，不过首选的方式，就像 Kernighan 和 Ritchie 展示
给我们的，是把起始大括号放在行尾，而把结束大括号放在行首，所以：

.. code-block:: c

	if (x is true) {
		we do y
	}

这适用于所有的非函数语句块 (if, switch, for, while, do)。比如：

.. code-block:: c

	switch (action) {
	case KOBJ_ADD:
		return "add";
	case KOBJ_REMOVE:
		return "remove";
	case KOBJ_CHANGE:
		return "change";
	default:
		return NULL;
	}

不过，有一个例外，那就是函数：函数的起始大括号放置于下一行的开头，所以：

.. code-block:: c

	int function(int x)
	{
		body of function
	}

全世界的异端可能会抱怨这个不一致性是……呃……不一致，不过所有思维健全的人
都知道 (a) K&R 是 **正确的** 并且 (b) K&R 是正确的。此外，不管怎样函数都是特
殊的 (C 函数是不能嵌套的)。

注意结束大括号独自占据一行，除非它后面跟着同一个语句的剩余部分，也就是 do 语
句中的 ``while`` 或者 if 语句中的 ``else`` ，像这样：

.. code-block:: c

	do {
		body of do-loop
	} while (condition);

和

.. code-block:: c

	if (x == y) {
		..
	} else if (x > y) {
		...
	} else {
		....
	}

理由：K&R。

也请注意这种大括号的放置方式也能使空 (或者差不多空的) 行的数量最小化，同时不
失可读性。因此，由于你的屏幕上的新行是不可再生资源 (想想 25 行的终端屏幕)，你
将会有更多的空行来放置注释。

当只有一个单独的语句的时候，不用加不必要的大括号。

.. code-block:: c

	if (condition)
		action();

和

.. code-block:: c

	if (condition)
		do_this();
	else
		do_that();

这并不适用于只有一个条件分支是单语句的情况；这时所有分支都要使用大括号：

.. code-block:: c

	if (condition) {
		do_this();
		do_that();
	} else {
		otherwise();
	}

3.1) 空格
*********

Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字
后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__，这
些关键字某些程度上看起来更像函数 (它们在 Linux 里也常常伴随小括号而使用，尽管
在 C 里这样的小括号不是必需的，就像 ``struct fileinfo info;`` 声明过后的
``sizeof info``)。

所以在这些关键字之后放一个空格::

	if, switch, case, for, do, while

但是不要在 sizeof, typeof, alignof 或者 __attribute__ 这些关键字之后放空格。
例如，

.. code-block:: c

	s = sizeof(struct file);

不要在小括号里的表达式两侧加空格。这是一个 **反例** ：

.. code-block:: c

	s = sizeof( struct file );

当声明指针类型或者返回指针类型的函数时， ``*`` 的首选使用方式是使之靠近变量名
或者函数名，而不是靠近类型名。例子：

.. code-block:: c

	char *linux_banner;
	unsigned long long memparse(char *ptr, char **retptr);
	char *match_strdup(substring_t *s);

在大多数二元和三元操作符两侧使用一个空格，例如下面所有这些操作符::

	=  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :

但是一元操作符后不要加空格::

	&  *  +  -  ~  !  sizeof  typeof  alignof  __attribute__  defined

后缀自加和自减一元操作符前不加空格::

	++  --

前缀自加和自减一元操作符后不加空格::

	++  --

``.`` 和 ``->`` 结构体成员操作符前后不加空格。

不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白，然后
你就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码，有些编辑器
就不会移除已经加入的空白，就像你故意留下一个只有空白的行。包含行尾空白的行就
这样产生了。

当 git 发现补丁包含了行尾空白的时候会警告你，并且可以应你的要求去掉行尾空白；
不过如果你是正在打一系列补丁，这样做会导致后面的补丁失败，因为你改变了补丁的
上下文。

4) 命名
-------

C 是一个简朴的语言，你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同，
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
称那个变量为 ``tmp`` ，这样写起来会更容易，而且至少不会令其难于理解。

不过，虽然混用大小写的名字是不提倡使用的，但是全局变量还是需要一个具描述性的
名字。称一个全局函数为 ``foo`` 是一个难以饶恕的错误。

全局变量 (只有当你 **真正** 需要它们的时候再用它) 需要有一个具描述性的名字，就
像全局函数。如果你有一个可以计算活动用户数量的函数，你应该叫它
``count_active_users()`` 或者类似的名字，你不应该叫它 ``cntuser()`` 。

在函数名中包含函数类型 (所谓的匈牙利命名法) 是脑子出了问题——编译器知道那些类
型而且能够检查那些类型，这样做只能把程序员弄糊涂了。

本地变量名应该简短，而且能够表达相关的含义。如果你有一些随机的整数型的循环计
数器，它应该被称为 ``i`` 。叫它 ``loop_counter`` 并无益处，如果它没有被误解的
可能的话。类似的， ``tmp`` 可以用来称呼任意类型的临时变量。

如果你怕混淆了你的本地变量名，你就遇到另一个问题了，叫做函数增长荷尔蒙失衡综
合征。请看第六章 (函数)。

对于符号名称和文档，避免引入新的“master/slave”（或独立于“master”的“slave”）
和“blacklist/whitelist”。

“master/slave”推荐替换为：
    '{primary,main} / {secondary,replica,subordinate}'
    '{initiator,requester} / {target,responder}'
    '{controller,host} / {device,worker,proxy}'
    'leader/follower'
    'director/performer'

“blacklist/whitelist”推荐替换为：
    'denylist/allowlist'
    'blocklist/passlist'

引入新用法的例外情况是：维护用户空间ABI/API，或更新现有（截至2020年）硬件或
协议规范的代码时要求这些术语。对于新规范，尽可能将术语的规范用法转换为内核
编码标准。

.. warning::
	以上主从、黑白名单规则不适用于中文文档，请勿更改中文术语！

5) Typedef
----------

不要使用类似 ``vps_t`` 之类的东西。

对结构体和指针使用 typedef 是一个 **错误** 。当你在代码里看到：

.. code-block:: c

	vps_t a;

这代表什么意思呢？

相反，如果是这样

.. code-block:: c

	struct virtual_container *a;

你就知道 ``a`` 是什么了。

很多人认为 typedef ``能提高可读性`` 。实际不是这样的。它们只在下列情况下有用：

 (a) 完全不透明的对象 (这种情况下要主动使用 typedef 来 **隐藏** 这个对象实际上
     是什么)。

     例如： ``pte_t`` 等不透明对象，你只能用合适的访问函数来访问它们。

     .. note::

       不透明性和“访问函数”本身是不好的。我们使用 pte_t 等类型的原因在于真
       的是完全没有任何共用的可访问信息。

 (b) 清楚的整数类型，如此，这层抽象就可以 **帮助** 消除到底是 ``int`` 还是
     ``long`` 的混淆。

     u8/u16/u32 是完全没有问题的 typedef，不过它们更符合类别 (d) 而不是这里。

     .. note::

       要这样做，必须事出有因。如果某个变量是 ``unsigned long`` ，那么没有必要

	typedef unsigned long myflags_t;

     不过如果有一个明确的原因，比如它在某种情况下可能会是一个 ``unsigned int``
     而在其他情况下可能为 ``unsigned long`` ，那么就不要犹豫，请务必使用
     typedef。

 (c) 当你使用 sparse 按字面的创建一个 **新** 类型来做类型检查的时候。

 (d) 和标准 C99 类型相同的类型，在某些例外的情况下。

     虽然让眼睛和脑筋来适应新的标准类型比如 ``uint32_t`` 不需要花很多时间，可
     是有些人仍然拒绝使用它们。

     因此，Linux 特有的等同于标准类型的 ``u8/u16/u32/u64`` 类型和它们的有符号
     类型是被允许的——尽管在你自己的新代码中，它们不是强制要求要使用的。

     当编辑已经使用了某个类型集的已有代码时，你应该遵循那些代码中已经做出的选
     择。

 (e) 可以在用户空间安全使用的类型。

     在某些用户空间可见的结构体里，我们不能要求 C99 类型而且不能用上面提到的
     ``u32`` 类型。因此，我们在与用户空间共享的所有结构体中使用 __u32 和类似
     的类型。

可能还有其他的情况，不过基本的规则是 **永远不要** 使用 typedef，除非你可以明
确的应用上述某个规则中的一个。

总的来说，如果一个指针或者一个结构体里的元素可以合理的被直接访问到，那么它们
就不应该是一个 typedef。

6) 函数
-------

函数应该简短而漂亮，并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们
都知道 ISO/ANSI 屏幕大小是 80x24)，只做一件事情，而且把它做好。

一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以，如果你有一个理
论上很简单的只有一个很长 (但是简单) 的 case 语句的函数，而且你需要在每个 case
里做很多很小的事情，这样的函数尽管很长，但也是可以的。

不过，如果你有一个复杂的函数，而且你怀疑一个天分不是很高的高中一年级学生可能
甚至搞不清楚这个函数的目的，你应该严格遵守前面提到的长度限制。使用辅助函数，
并为之取个具描述性的名字 (如果你觉得它们的性能很重要的话，可以让编译器内联它
们，这样的效果往往会比你写一个复杂函数的效果要好。)

函数的另外一个衡量标准是本地变量的数量。此数量不应超过 5－10 个，否则你的函数
就有问题了。重新考虑一下你的函数，把它分拆成更小的函数。人的大脑一般可以轻松
的同时跟踪 7 个不同的事物，如果再增多的话，就会糊涂了。即便你聪颖过人，你也可
能会记不清你 2 个星期前做过的事情。

在源文件里，使用空行隔开不同的函数。如果该函数需要被导出，它的 **EXPORT** 宏
应该紧贴在它的结束大括号之下。比如：

.. code-block:: c

	int system_is_up(void)
	{
		return system_state == SYSTEM_RUNNING;
	}
	EXPORT_SYMBOL(system_is_up);

6.1) 函数原型
*************

在函数原型中包含参数名和它们的数据类型。虽然 C 语言里没有这样的要求，但在
Linux 里这是提倡的做法，因为这样可以很简单的给读者提供更多的有价值的信息。

不要在函数声明里使用 ``extern`` 关键字，因为这会导致代码行变长，并且不是严格
必需的。

写函数原型时，请保持 `元素顺序规则 <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_ 。
例如下列函数声明::

 __init void * __must_check action(enum magic value, size_t size, u8 count,
				   char *fmt, ...) __printf(4, 5) __malloc;

推荐的函数原型元素顺序是：

- 储存类型（下方的 ``static __always_inline`` ，注意 ``__always_inline``
  技术上来讲是个属性但被当做 ``inline`` ）
- 储存类型属性（上方的 ``__init`` ——即节声明，但也像 ``__cold`` ）
- 返回类型（上方的 ``void *`` ）
- 返回类型属性（上方的 ``__must_check`` ）
- 函数名（上方的 ``action`` ）
- 函数参数（上方的 ``(enum magic value, size_t size, u8 count, char *fmt, ...)`` ，
  注意必须写上参数名）
- 函数参数属性（上方的 ``__printf(4, 5)`` ）
- 函数行为属性（上方的 ``__malloc`` ）

请注意，对于函数 **定义** （即实际函数体），编译器不允许在函数参数之后添加函
数参数属性。在这种情况下，它们应该跟随存储类型属性（例如，与上面的 **声明**
示例相比，请注意下面的 ``__printf(4, 5)`` 的位置发生了变化）::

 static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
		size_t size, u8 count, char *fmt, ...) __malloc
 {
	...
 }

7) 集中的函数退出途径
---------------------

虽然被某些人声称已经过时，但是 goto 语句的等价物还是经常被编译器所使用，具体
形式是无条件跳转指令。

当一个函数从多个位置退出，并且需要做一些类似清理的常见操作时，goto 语句就很方
便了。如果并不需要清理操作，那么直接 return 即可。

选择一个能够说明 goto 行为或它为何存在的标签名。如果 goto 要释放 ``buffer``,
一个不错的名字可以是 ``out_free_buffer:`` 。别去使用像 ``err1:`` 和 ``err2:``
这样的GW_BASIC 名称，因为一旦你添加或删除了 (函数的) 退出路径，你就必须对它们
重新编号，这样会难以去检验正确性。

使用 goto 的理由是：

- 无条件语句容易理解和跟踪
- 嵌套程度减小
- 可以避免由于修改时忘记更新个别的退出点而导致错误
- 让编译器省去删除冗余代码的工作 ;)

.. code-block:: c

	int fun(int a)
	{
		int result = 0;
		char *buffer;

		buffer = kmalloc(SIZE, GFP_KERNEL);
		if (!buffer)
			return -ENOMEM;

		if (condition1) {
			while (loop1) {
				...
			}
			result = 1;
			goto out_free_buffer;
		}
		...
	out_free_buffer:
		kfree(buffer);
		return result;
	}

一个需要注意的常见错误是 ``单 err 错误`` ，就像这样：

.. code-block:: c

	err:
		kfree(foo->bar);
		kfree(foo);
		return ret;

这段代码的错误是，在某些退出路径上 ``foo`` 是 NULL。通常情况下，通过把它分离
成两个错误标签 ``err_free_bar:`` 和 ``err_free_foo:`` 来修复这个错误：

.. code-block:: c

	 err_free_bar:
		kfree(foo->bar);
	 err_free_foo:
		kfree(foo);
		return ret;

理想情况下，你应该模拟错误来测试所有退出路径。

8) 注释
-------

注释是好的，不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的：
更好的做法是让别人一看你的代码就可以明白，解释写的很差的代码是浪费时间。

一般来说你用注释告诉别人你的代码做了什么，而不是怎么做的。也请你不要把
注释放在一个函数体内部：如果函数复杂到你需要独立的注释其中的一部分，你很可能
需要回到第六章看一看。你可以做一些小注释来注明或警告某些很聪明 (或者槽糕) 的
做法，但不要加太多。你应该做的，是把注释放在函数的头部，告诉人们它做了什么，
也可以加上它做这些事情的原因。

当注释内核 API 函数时，请使用 kernel-doc 格式。详见
Documentation/translations/zh_CN/doc-guide/index.rst 和 scripts/kernel-doc 。

长 (多行) 注释的首选风格是：

.. code-block:: c

	/*
	 * This is the preferred style for multi-line
	 * comments in the Linux kernel source code.
	 * Please use it consistently.
	 *
	 * Description:  A column of asterisks on the left side,
	 * with beginning and ending almost-blank lines.
	 */

对于在 net/ 和 drivers/net/ 的文件，首选的长 (多行) 注释风格有些不同。

.. code-block:: c

	/* The preferred comment style for files in net/ and drivers/net
	 * looks like this.
	 *
	 * It is nearly the same as the generally preferred comment style,
	 * but there is no initial almost-blank line.
	 */

注释数据也是很重要的，不管是基本类型还是衍生类型。为了方便实现这一点，每一行
应只声明一个数据 (不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据
写一段小注释来解释它们的用途了。

9) 你已经把事情弄糟了
---------------------

这没什么，我们都是这样。可能你长期使用 Unix 的朋友已经告诉你
``GNU emacs`` 能自动帮你格式化 C 源代码，而且你也注意到了，确实是这样，不过它
所使用的默认值和我们想要的相去甚远 (实际上，甚至比随机打的还要差——无数个猴子
在 GNU emacs 里打字永远不会创造出一个好程序)
*(译注：Infinite Monkey Theorem)*

所以你要么放弃 GNU emacs，要么改变它让它使用更合理的设定。要采用后一个方案，
你可以把下面这段粘贴到你的 .emacs 文件里。

.. code-block:: elisp

  (defun c-lineup-arglist-tabs-only (ignored)
    "Line up argument lists by tabs, not spaces"
    (let* ((anchor (c-langelem-pos c-syntactic-element))
           (column (c-langelem-2nd-pos c-syntactic-element))
           (offset (- (1+ column) anchor))
           (steps (floor offset c-basic-offset)))
      (* (max steps 1)
         c-basic-offset)))

  (dir-locals-set-class-variables
   'linux-kernel
   '((c-mode . (
          (c-basic-offset . 8)
          (c-label-minimum-indentation . 0)
          (c-offsets-alist . (
                  (arglist-close         . c-lineup-arglist-tabs-only)
                  (arglist-cont-nonempty .
                      (c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
                  (arglist-intro         . +)
                  (brace-list-intro      . +)
                  (c                     . c-lineup-C-comments)
                  (case-label            . 0)
                  (comment-intro         . c-lineup-comment)
                  (cpp-define-intro      . +)
                  (cpp-macro             . -1000)
                  (cpp-macro-cont        . +)
                  (defun-block-intro     . +)
                  (else-clause           . 0)
                  (func-decl-cont        . +)
                  (inclass               . +)
                  (inher-cont            . c-lineup-multi-inher)
                  (knr-argdecl-intro     . 0)
                  (label                 . -1000)
                  (statement             . 0)
                  (statement-block-intro . +)
                  (statement-case-intro  . +)
                  (statement-cont        . +)
                  (substatement          . +)
                  ))
          (indent-tabs-mode . t)
          (show-trailing-whitespace . t)
          ))))

  (dir-locals-set-directory-class
   (expand-file-name "~/src/linux-trees")
   'linux-kernel)

这会让 emacs 在 ``~/src/linux-trees`` 下的 C 源文件获得更好的内核代码风格。

不过就算你尝试让 emacs 正确的格式化代码失败了，也并不意味着你失去了一切：还可
以用 ``indent`` 。

不过，GNU indent 也有和 GNU emacs 一样有问题的设定，所以你需要给它一些命令选
项。不过，这还不算太糟糕，因为就算是 GNU indent 的作者也认同 K&R 的权威性
(GNU 的人并不是坏人，他们只是在这个问题上被严重的误导了)，所以你只要给 indent
指定选项 ``-kr -i8`` (代表 ``K&R，8 字符缩进``)，或使用 ``scripts/Lindent``
这样就可以以最时髦的方式缩进源代码。

``indent`` 有很多选项，特别是重新格式化注释的时候，你可能需要看一下它的手册。
不过记住： ``indent`` 不能修正坏的编程习惯。

请注意，您还可以使用 ``clang-format`` 工具帮助您处理这些规则，快速自动重新格
式化部分代码，并审阅整个文件以发现代码风格错误、打字错误和可能的改进。它还可
以方便地排序 ``#include`` ，对齐变量/宏，重排文本和其他类似任务。
详见 Documentation/process/clang-format.rst 。

10) Kconfig 配置文件
--------------------

对于遍布源码树的所有 Kconfig* 配置文件来说，它们缩进方式有所不同。紧挨着
``config`` 定义的行，用一个制表符缩进，然而 help 信息的缩进则额外增加 2 个空
格。举个例子::

  config AUDIT
	bool "Auditing support"
	depends on NET
	help
	  Enable auditing infrastructure that can be used with another
	  kernel subsystem, such as SELinux (which requires this for
	  logging of avc messages output).  Does not do system-call
	  auditing without CONFIG_AUDITSYSCALL.

而那些危险的功能 (比如某些文件系统的写支持) 应该在它们的提示字符串里显著的声
明这一点::

  config ADFS_FS_RW
	bool "ADFS write support (DANGEROUS)"
	depends on ADFS_FS
	...

要查看配置文件的完整文档，请看 Documentation/kbuild/kconfig-language.rst 。

11) 数据结构
------------

如果一个数据结构，在创建和销毁它的单线执行环境之外可见，那么它必须要有一个引
用计数器。内核里没有垃圾收集 (并且内核之外的垃圾收集慢且效率低下)，这意味着你
绝对需要记录你对这种数据结构的使用情况。

引用计数意味着你能够避免上锁，并且允许多个用户并行访问这个数据结构——而不需要
担心这个数据结构仅仅因为暂时不被使用就消失了，那些用户可能不过是沉睡了一阵或
者做了一些其他事情而已。

注意上锁 **不能** 取代引用计数。上锁是为了保持数据结构的一致性，而引用计数是一
个内存管理技巧。通常二者都需要，不要把两个搞混了。

很多数据结构实际上有 2 级引用计数，它们通常有不同 ``类`` 的用户。子类计数器统
计子类用户的数量，每当子类计数器减至零时，全局计数器减一。

这种 ``多级引用计数`` 的例子可以在内存管理 (``struct mm_struct``: mm_users 和
mm_count)，和文件系统 (``struct super_block``: s_count 和 s_active) 中找到。

记住：如果另一个执行线索可以找到你的数据结构，但这个数据结构没有引用计数器，
这里几乎肯定是一个 bug。

12) 宏，枚举和RTL
-----------------

用于定义常量的宏的名字及枚举里的标签需要大写。

.. code-block:: c

	#define CONSTANT 0x12345

在定义几个相关的常量时，最好用枚举。

宏的名字请用大写字母，不过形如函数的宏的名字可以用小写字母。

通常如果能写成内联函数就不要写成像函数的宏。

含有多个语句的宏应该被包含在一个 do-while 代码块里：

.. code-block:: c

	#define macrofun(a, b, c)			\
		do {					\
			if (a == 5)			\
				do_this(b, c);		\
		} while (0)

使用宏的时候应避免的事情：

1) 影响控制流程的宏：

.. code-block:: c

	#define FOO(x)					\
		do {					\
			if (blah(x) < 0)		\
				return -EBUGGERED;	\
		} while (0)

**非常** 不好。它看起来像一个函数，不过却能导致 ``调用`` 它的函数退出；不要打
乱读者大脑里的语法分析器。

2) 依赖于一个固定名字的本地变量的宏：

.. code-block:: c

	#define FOO(val) bar(index, val)

可能看起来像是个不错的东西，不过它非常容易把读代码的人搞糊涂，而且容易导致看起
来不相关的改动带来错误。

3) 作为左值的带参数的宏： FOO(x) = y；如果有人把 FOO 变成一个内联函数的话，这
   种用法就会出错了。

4) 忘记了优先级：使用表达式定义常量的宏必须将表达式置于一对小括号之内。带参数
   的宏也要注意此类问题。

.. code-block:: c

	#define CONSTANT 0x4000
	#define CONSTEXP (CONSTANT | 3)

5) 在宏里定义类似函数的本地变量时命名冲突：

.. code-block:: c

	#define FOO(x)				\
	({					\
		typeof(x) ret;			\
		ret = calc_ret(x);		\
		(ret);				\
	})

ret 是本地变量的通用名字—— __foo_ret 更不容易与一个已存在的变量冲突。

cpp 手册对宏的讲解很详细。gcc internals 手册也详细讲解了 RTL，内核里的汇编语
言经常用到它。

13) 打印内核消息
----------------

内核开发者应该看起来有文化。请一定注意内核信息的拼写，以给人良好的印象。
不要用不规范的单词比如 ``dont``，而要用 ``do not`` 或者 ``don't`` 。保证这些信
息简单明了、无歧义。

内核信息不必以英文句号结束。

在小括号里打印数字 (%d) 没有任何价值，应该避免这样做。

<linux/device.h> 里有一些驱动模型诊断宏，你应该使用它们，以确保信息对应于正确
的设备和驱动，并且被标记了正确的消息级别。这些宏有：dev_err(), dev_warn(),
dev_info() 等等。对于那些不和某个特定设备相关连的信息，<linux/printk.h> 定义
了 pr_notice(), pr_info(), pr_warn(), pr_err() 和其他。

写出好的调试信息可以是一个很大的挑战；一旦你写出后，这些信息在远程除错时能提
供极大的帮助。然而打印调试信息的处理方式同打印非调试信息不同。其他 pr_XXX()
函数能无条件地打印，pr_debug() 却不；默认情况下它不会被编译，除非定义了 DEBUG
或设定了 CONFIG_DYNAMIC_DEBUG。实际这同样是为了 dev_dbg()，一个相关约定是在一
个已经开启了 DEBUG 时，使用 VERBOSE_DEBUG 来添加 dev_vdbg()。

许多子系统拥有 Kconfig 调试选项来开启对应 Makefile 里面的 -DDEBUG；在其他
情况下，特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时，例如，
如果已经包含一个调试相关的 #ifdef 条件，printk(KERN_DEBUG ...) 就可被使用。

14) 分配内存
------------

内核提供了下面的一般用途的内存分配函数：
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
请参考 API 文档以获取有关它们的详细信息：
Documentation/translations/zh_CN/core-api/memory-allocation.rst 。

传递结构体大小的首选形式是这样的：

.. code-block:: c

	p = kmalloc(sizeof(*p), ...);

另外一种传递方式中，sizeof 的操作数是结构体的名字，这样会降低可读性，并且可能
会引入 bug。有可能指针变量类型被改变时，而对应的传递给内存分配函数的 sizeof
的结果不变。

强制转换一个 void 指针返回值是多余的。C 语言本身保证了从 void 指针到其他任何
指针类型的转换是没有问题的。

分配一个数组的首选形式是这样的：

.. code-block:: c

	p = kmalloc_array(n, sizeof(...), ...);

分配一个零长数组的首选形式是这样的：

.. code-block:: c

	p = kcalloc(n, sizeof(...), ...);

两种形式都会检查分配 n * sizeof(...) 大小时内存的溢出，如果溢出返回 NULL。

在没有 __GFP_NOWARN 的情况下使用时，这些通用分配函数都会在失败时发起堆栈转储，
因此当返回NULL时，没有必要发出额外的失败消息。

15) 内联弊病
------------

有一个常见的误解是 ``内联`` 是 gcc 提供的可以让代码运行更快的一个选项。虽然使
用内联函数有时候是恰当的 (比如作为一种替代宏的方式，请看第十二章)，不过很多情
况下不是这样。inline 的过度使用会使内核变大，从而使整个系统运行速度变慢。
因为体积大内核会占用更多的指令高速缓存，而且会导致 pagecache 的可用内存减少。
想象一下，一次 pagecache 未命中就会导致一次磁盘寻址，将耗时 5 毫秒。5 毫秒的
时间内 CPU 能执行很多很多指令。

一个基本的原则是如果一个函数有 3 行以上，就不要把它变成内联函数。这个原则的一
个例外是，如果你知道某个参数是一个编译时常量，而且因为这个常量你确定编译器在
编译时能优化掉你的函数的大部分代码，那仍然可以给它加上 inline 关键字。
kmalloc() 内联函数就是一个很好的例子。

人们经常主张给 static 的而且只用了一次的函数加上 inline，如此不会有任何损失，
因为没有什么好权衡的。虽然从技术上说这是正确的，但是实际上这种情况下即使不加
inline gcc 也可以自动使其内联。而且其他用户可能会要求移除 inline，由此而来的
争论会抵消 inline 自身的潜在价值，得不偿失。

16) 函数返回值及命名
--------------------

函数可以返回多种不同类型的值，最常见的一种是表明函数执行成功或者失败的值。这样
的一个值可以表示为一个错误代码整数 (-Exxx＝失败，0＝成功) 或者一个 ``成功``
布尔值 (0＝失败，非0＝成功)。

混合使用这两种表达方式是难于发现的 bug 的来源。如果 C 语言本身严格区分整形和
布尔型变量，那么编译器就能够帮我们发现这些错误... 不过 C 语言不区分。为了避免
产生这种 bug，请遵循下面的惯例::

	如果函数的名字是一个动作或者强制性的命令，那么这个函数应该返回错误代
	码整数。如果是一个判断，那么函数应该返回一个“成功”布尔值。

比如， ``add work`` 是一个命令，所以 add_work() 在成功时返回 0，在失败时返回
-EBUSY。类似的，因为 ``PCI device present`` 是一个判断，所以 pci_dev_present()
在成功找到一个匹配的设备时应该返回 1，如果找不到时应该返回 0。

所有 EXPORTed 函数都必须遵守这个惯例，所有的公共函数也都应该如此。私有
(static) 函数不需要如此，但是我们也推荐这样做。

返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。通常
他们通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数，
他们使用 NULL 或者 ERR_PTR 机制来报告错误。

17) 使用布尔类型
----------------

Linux内核布尔（bool）类型是C99 _Bool类型的别名。布尔值只能为0或1，而对布尔的
隐式或显式转换将自动将值转换为true或false。在使用布尔类型时 **不需要** 构造，
它会消除一类错误。

使用布尔值时，应使用true和false定义，而不是1和0。

布尔函数返回类型和堆栈变量总是可以在适当的时候使用。鼓励使用布尔来提高可读性，
并且布尔值在存储时通常比“int”更好。

如果缓存行布局或值的大小很重要，请不要使用布尔，因为其大小和对齐方式根据编译
的体系结构而不同。针对对齐和大小进行优化的结构体不应使用布尔。

如果一个结构体有多个true/false值，请考虑将它们合并为具有1比特成员的位域，或使
用适当的固定宽度类型，如u8。

类似地，对于函数参数，多个true/false值可以合并为单个按位的“标志”参数，如果调
用点具有裸true/false常量，“标志”参数通常是更具可读性的替代方法。

总之，在结构体和参数中有限地使用布尔可以提高可读性。

18) 不要重新发明内核宏
----------------------

头文件 include/linux/kernel.h 包含了一些宏，你应该使用它们，而不要自己写一些
它们的变种。比如，如果你需要计算一个数组的长度，使用这个宏

.. code-block:: c

	#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

类似的，如果你要计算某结构体成员的大小，使用

.. code-block:: c

	#define sizeof_field(t, f) (sizeof(((t*)0)->f))

还有可以做严格的类型检查的 min() 和 max() 宏，如果你需要可以使用它们。你可以
自己看看那个头文件里还定义了什么你可以拿来用的东西，如果有定义的话，你就不应
在你的代码里自己重新定义。

19) 编辑器模式行和其他需要罗嗦的事情
------------------------------------

有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如，emacs
能够解析被标记成这样的行：

.. code-block:: c

	-*- mode: c -*-

或者这样的：

.. code-block:: c

	/*
	Local Variables:
	compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
	End:
	*/

Vim 能够解析这样的标记：

.. code-block:: c

	/* vim:set sw=8 noet */

不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置，你的源文件不
应该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制
的模式，或者使用其他可以产生正确的缩进的巧妙方法。

20) 内联汇编
------------

在特定架构的代码中，你可能需要内联汇编与 CPU 和平台相关功能连接。需要这么做时
就不要犹豫。然而，当 C 可以完成工作时，不要平白无故地使用内联汇编。在可能的情
况下，你可以并且应该用 C 和硬件沟通。

请考虑去写捆绑通用位元 (wrap common bits) 的内联汇编的简单辅助函数，别去重复
地写下只有细微差异内联汇编。记住内联汇编可以使用 C 参数。

大型，有一定复杂度的汇编函数应该放在 .S 文件内，用相应的 C 原型定义在 C 头文
件中。汇编函数的 C 原型应该使用 ``asmlinkage`` 。

你可能需要把汇编语句标记为 volatile，用来阻止 GCC 在没发现任何副作用后就把它
移除了。你不必总是这样做，尽管，这不必要的举动会限制优化。

在写一个包含多条指令的单个内联汇编语句时，把每条指令用引号分割而且各占一行，
除了最后一条指令外，在每个指令结尾加上 ``\n\t`` ，让汇编输出时可以正确地缩进
下一条指令：

.. code-block:: c

	asm ("magic %reg1, #42\n\t"
	     "more_magic %reg2, %reg3"
	     : /* outputs */ : /* inputs */ : /* clobbers */);

21) 条件编译
------------

只要可能，就不要在 .c 文件里面使用预处理条件 (#if, #ifdef)；这样做会让代码更难
阅读并且更难去跟踪逻辑。替代方案是，在头文件中用预处理条件提供给那些 .c 文件
使用，再给 #else 提供一个空桩 (no-op stub) 版本，然后在 .c 文件内无条件地调用
那些 (定义在头文件内的) 函数。这样做，编译器会避免为桩函数 (stub) 的调用生成
任何代码，产生的结果是相同的，但逻辑将更加清晰。

最好倾向于编译整个函数，而不是函数的一部分或表达式的一部分。与其放一个 ifdef
在表达式内，不如分解出部分或全部表达式，放进一个单独的辅助函数，并应用预处理
条件到这个辅助函数内。

如果你有一个在特定配置中，可能变成未使用的函数或变量，编译器会警告它定义了但
未使用，请把它标记为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而，
如果一个函数或变量总是未使用，就直接删除它。)

在代码中，尽可能地使用 IS_ENABLED 宏来转化某个 Kconfig 标记为 C 的布尔
表达式，并在一般的 C 条件中使用它：

.. code-block:: c

	if (IS_ENABLED(CONFIG_SOMETHING)) {
		...
	}

编译器会做常量折叠，然后就像使用 #ifdef 那样去包含或排除代码块，所以这不会带
来任何运行时开销。然而，这种方法依旧允许 C 编译器查看块内的代码，并检查它的正
确性 (语法，类型，符号引用，等等)。因此，如果条件不满足，代码块内的引用符号就
不存在时，你还是必须去用 #ifdef。

在任何有意义的 #if 或 #ifdef 块的末尾 (超过几行的)，在 #endif 同一行的后面写下
注解，注释这个条件表达式。例如：

.. code-block:: c

	#ifdef CONFIG_SOMETHING
	...
	#endif /* CONFIG_SOMETHING */

附录 I) 参考资料
----------------

The C Programming Language, 2nd Edition
作者：Brian W. Kernighan 和 Denni M. Ritchie.
Prentice Hall, Inc., 1988.
ISBN 0-13-110362-8 (平装), 0-13-110370-9 (精装).

.. note::

    《C程序设计语言（第2版）》
    作者：[美] Brian W. Kernighan / [美] Dennis M. Ritchie
    译者：徐宝文 / 李志 / 尤晋元（审校）
    出版社：机械工业出版社，2019
    ISBN：9787111617945

The Practice of Programming
作者：Brian W. Kernighan 和 Rob Pike.
Addison-Wesley, Inc., 1999.
ISBN 0-201-61586-X.

.. note::

    《程序设计实践》
    作者：[美] Brian W. Kernighan / [美] Rob Pike
    出版社：机械工业出版社，2005
    ISBN：9787111091578

    《程序设计实践》
    作者：[美] Brian W. Kernighan / Rob Pike
    译者：裘宗燕
    出版社：机械工业出版社，2000
    ISBN：9787111075738

GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
都可以从 https://www.gnu.org/manual/ 找到

WG14 是 C 语言的国际标准化工作组，URL: http://www.open-std.org/JTC1/SC22/WG14/

内核文档 Documentation/process/coding-style.rst，
作者 greg@kroah.com 发表于 OLS 2002：
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/


code:
.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/development-process.rst <development_process_main>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

.. _cn_development_process_main:

内核开发过程指南
================

内容:

.. toctree::
   :numbered:
   :maxdepth: 2

   1.Intro
   2.Process
   3.Early-stage
   4.Coding
   5.Posting
   6.Followthrough
   7.AdvancedTopics
   8.Conclusion

本文档的目的是帮助开发人员（及其经理）以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发（或者实际上是自由软件开发）的人可以访问的方式工作。虽然这里有一些技术资料，但这是一个面向过程的讨论，不需要深入了解内核编程就可以理解。

repo_name: angery/linux


code:
.. SPDX-License-Identifier: GPL-2.0-or-later

.. include:: ../disclaimer-zh_CN.rst

.. _cn_email_clients:

:Original: Documentation/process/email-clients.rst

:译者:
 - 贾威威  Harry Wei <harryxiyou@gmail.com>
 - 时奎亮  Alex Shi <alexs@kernel.org>
 - 吴想成  Wu XiangCheng <bobwxc@email.cn>

:校译:
 - Yinglin Luan <synmyth@gmail.com>
 - Xiaochen Wang <wangxiaochen0@gmail.com>
 - yaxinsn <yaxinsn@163.com>

Linux邮件客户端配置信息
=======================

Git
---

现在大多数开发人员使用 ``git send-email`` 而不是常规的电子邮件客户端。这方面
的手册非常好。在接收端，维护人员使用 ``git am`` 加载补丁。

如果你是 ``git`` 新手，那么把你的第一个补丁发送给你自己。将其保存为包含所有
标题的原始文本。运行 ``git am raw_email.txt`` ，然后使用 ``git log`` 查看更
改日志。如果工作正常，再将补丁发送到相应的邮件列表。

通用配置
--------

Linux内核补丁是通过邮件被提交的，最好把补丁作为邮件体的内嵌文本。有些维护者
接收附件，但是附件的内容格式应该是"text/plain"。然而，附件一般是不赞成的，
因为这会使补丁的引用部分在评论过程中变的很困难。

同时也强烈建议在补丁或其他邮件的正文中使用纯文本格式。https://useplaintext.email
有助于了解如何配置你喜欢的邮件客户端，并在您还没有首选的情况下列出一些推荐的
客户端。

用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如，
他们不能改变或者删除制表符或者空格，甚至是在每一行的开头或者结尾。

不要通过"format=flowed"模式发送补丁。这样会引起不可预期以及有害的断行。

不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。

邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码
方式，如果你使用UTF-8编码方式发送邮件，那么你将会避免一些可能发生的字符集问题。

邮件客户端应该生成并且保持“References:”或者“In-Reply-To:”邮件头，这样邮件会话
就不会中断。

复制粘帖(或者剪贴粘帖)通常不能用于补丁，因为制表符会转换为空格。使用xclipboard,
xclip或者xcutsel也许可以，但是最好测试一下或者避免使用复制粘帖。

不要在使用PGP/GPG签名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的
补丁。（这个问题应该是可以修复的）

在给内核邮件列表发送补丁之前，给自己发送一个补丁是个不错的主意，保存接收到的
邮件，将补丁用'patch'命令打上，如果成功了，再给内核邮件列表发送。

一些邮件客户端提示
------------------

这里给出一些详细的MUA配置提示，可以用于给Linux内核发送补丁。这些并不意味是
所有的软件包配置总结。

说明：

- TUI = 以文本为基础的用户接口
- GUI = 图形界面用户接口

Alpine (TUI)
************

配置选项：

在 :menuselection:`Sending Preferences` 菜单：

- :menuselection:`Do Not Send Flowed Text` 必须开启
- :menuselection:`Strip Whitespace Before Sending` 必须关闭

当写邮件时，光标应该放在补丁会出现的地方，然后按下 :kbd:`CTRL-R` 组合键，使指
定的补丁文件嵌入到邮件中。

Claws Mail (GUI)
****************

可以用，有人用它成功地发过补丁。

用 :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) 或外置编辑器插入补丁。

若要在Claws编辑窗口重修改插入的补丁，需关闭
:menuselection:`Configuration-->Preferences-->Compose-->Wrapping`
的 `Auto wrapping` 。

Evolution (GUI)
***************

一些开发者成功的使用它发送补丁。

撰写邮件时：
从 :menuselection:`格式-->段落样式-->预格式化` (:kbd:`CTRL-7`)
或工具栏选择 :menuselection:`预格式化` ；

然后使用：
:menuselection:`插入-->文本文件...` (:kbd:`ALT-N x`) 插入补丁文件。

你还可以 ``diff -Nru old.c new.c | xclip`` ，选择 :menuselection:`预格式化` ，
然后使用鼠标中键进行粘帖。

Kmail (GUI)
***********

一些开发者成功的使用它发送补丁。

默认撰写设置禁用HTML格式是合适的；不要启用它。

当书写一封邮件的时候，在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输
入的任何文本都不会被自动换行，因此你必须在发送补丁之前手动换行。最简单的方法
就是启用自动换行来书写邮件，然后把它保存为草稿。一旦你在草稿中再次打开它，它
已经全部自动换行了，那么你的邮件虽然没有选择自动换行，但是还不会失去已有的自
动换行。

在邮件的底部，插入补丁之前，放上常用的补丁定界符：三个连字符(``---``)。

然后在 :menuselection:`信件` 菜单，选择 :menuselection:`插入文本文件` ，接
着选取你的补丁文件。还有一个额外的选项，你可以通过它配置你的创建新邮件工具栏，
加上 :menuselection:`插入文本文件` 图标。

将编辑器窗口拉到足够宽避免折行。对于KMail 1.13.5 (KDE 4.5.4)，它会在发送邮件
时对编辑器窗口中显示折行的地方自动换行。在选项菜单中取消自动换行仍不能解决。
因此，如果你的补丁中有非常长的行，必须在发送之前把编辑器窗口拉得非常宽。
参见：https://bugs.kde.org/show_bug.cgi?id=174034

你可以安全地用GPG签名附件，但是内嵌补丁最好不要使用GPG签名它们。作为内嵌文本
插入的签名补丁将使其难以从7-bit编码中提取。

如果你非要以附件的形式发送补丁，那么就右键点击附件，然后选择
:menuselection:`属性` ，打开 :menuselection:`建议自动显示` ，使附件内联更容
易让读者看到。

当你要保存将要发送的内嵌文本补丁，你可以从消息列表窗格选择包含补丁的邮件，然
后右键选择 :menuselection:`另存为` 。如果整个电子邮件的组成正确，您可直接将
其作为补丁使用。电子邮件以当前用户可读写权限保存，因此您必须 ``chmod`` ，以
使其在复制到别处时用户组和其他人可读。

Lotus Notes (GUI)
*****************

不要使用它。

IBM Verse (Web GUI)
*******************

同上条。

Mutt (TUI)
**********

很多Linux开发人员使用mutt客户端，这证明它肯定工作得非常漂亮。

Mutt不自带编辑器，所以不管你使用什么编辑器，不自动断行就行。大多数编辑器都有
:menuselection:`插入文件` 选项，它可以在不改变文件内容的情况下插入文件。

用 ``vim`` 作为mutt的编辑器::

  set editor="vi"

如果使用xclip，敲入以下命令::

  :set paste

然后再按中键或者shift-insert或者使用::

  :r filename

把补丁插入为内嵌文本。
在未设置  ``set paste`` 时(a)ttach工作的很好。

你可以通过 ``git format-patch`` 生成补丁，然后用 Mutt发送它们::

    $ mutt -H 0001-some-bug-fix.patch

配置选项：

它应该以默认设置的形式工作。
然而，把 ``send_charset`` 设置一下也是一个不错的主意::

  set send_charset="us-ascii:utf-8"

Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置::

  # .muttrc
  # ================  IMAP ====================
  set imap_user = 'yourusername@gmail.com'
  set imap_pass = 'yourpassword'
  set spoolfile = imaps://imap.gmail.com/INBOX
  set folder = imaps://imap.gmail.com/
  set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
  set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
  set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"

  # ================  SMTP  ====================
  set smtp_url = "smtp://username@smtp.gmail.com:587/"
  set smtp_pass = $imap_pass
  set ssl_force_tls = yes # Require encrypted connection

  # ================  Composition  ====================
  set editor = `echo \$EDITOR`
  set edit_headers = yes  # See the headers when editing
  set charset = UTF-8     # value of $LANG; also fallback for send_charset
  # Sender, email address, and sign-off line must match
  unset use_domain        # because joe@localhost is just embarrassing
  set realname = "YOUR NAME"
  set from = "username@gmail.com"
  set use_from = yes

Mutt文档含有更多信息：

    https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail

    http://www.mutt.org/doc/manual/

Pine (TUI)
**********

Pine过去有一些空格删减问题，但是这些现在应该都被修复了。

如果可以，请使用alpine（pine的继承者）。

配置选项：

- 最近的版本需要 ``quell-flowed-text``
- ``no-strip-whitespace-before-send`` 选项也是需要的。

Sylpheed (GUI)
**************

- 内嵌文本可以很好的工作（或者使用附件）。
- 允许使用外部的编辑器。
- 收件箱较多时非常慢。
- 如果通过non-SSL连接，无法使用TLS SMTP授权。
- 撰写窗口的标尺很有用。
- 将地址添加到通讯簿时无法正确理解显示的名称。

Thunderbird (GUI)
*****************

Thunderbird是Outlook的克隆版本，它很容易损坏文本，但也有一些方法强制修正。

在完成修改后（包括安装扩展），您需要重新启动Thunderbird。

- 允许使用外部编辑器：

  使用Thunderbird发补丁最简单的方法是使用扩展来打开您最喜欢的外部编辑器。

  下面是一些能够做到这一点的扩展样例。

  - “External Editor Revived”

    https://github.com/Frederick888/external-editor-revived

    https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/

    它需要安装“本地消息主机（native messaging host）”。
    参见以下文档:
    https://github.com/Frederick888/external-editor-revived/wiki

  - “External Editor”

    https://github.com/exteditor/exteditor

    下载并安装此扩展，然后打开 :menuselection:`新建消息` 窗口, 用
    :menuselection:`查看-->工具栏-->自定义...` 给它增加一个按钮，直接点击此
    按钮即可使用外置编辑器。

    请注意，“External Editor”要求你的编辑器不能fork，换句话说，编辑器必须在
    关闭前不返回。你可能需要传递额外的参数或修改编辑器设置。最值得注意的是，
    如果您使用的是gvim，那么您必须将 :menuselection:`external editor` 设置的
    编辑器字段设置为 ``/usr/bin/gvim --nofork"`` （假设可执行文件在
    ``/usr/bin`` ），以传递 ``-f`` 参数。如果您正在使用其他编辑器，请阅读其
    手册了解如何处理。

若要修正内部编辑器，请执行以下操作：

- 修改你的Thunderbird设置，不要使用 ``format=flowed`` ！
  回到主窗口，按照
  :menuselection:`主菜单-->首选项-->常规-->配置编辑器...`
  打开Thunderbird的配置编辑器。

  - 将 ``mailnews.send_plaintext_flowed`` 设为 ``false``

  - 将 ``mailnews.wraplength`` 从 ``72`` 改为 ``0``

- 不要写HTML邮件！
  回到主窗口，打开
  :menuselection:`主菜单-->账户设置-->你的@邮件.地址-->通讯录/编写&地址簿` ，
  关掉 ``以HTML格式编写消息`` 。

- 只用纯文本格式查看邮件！
  回到主窗口， :menuselection:`主菜单-->查看-->消息体为-->纯文本` ！

TkRat (GUI)
***********

可以使用它。使用"Insert file..."或者外部的编辑器。

Gmail (Web GUI)
***************

不要使用它发送补丁。

Gmail网页客户端自动地把制表符转换为空格。

虽然制表符转换为空格问题可以被外部编辑器解决，但它同时还会使用回车换行把每行
拆分为78个字符。

另一个问题是Gmail还会把任何含有非ASCII的字符的消息改用base64编码，如欧洲人的
名字。


code:
.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/embargoed-hardware-issues.rst <embargoed_hardware_issues>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

被限制的硬件问题
================

范围
----

导致安全问题的硬件问题与只影响Linux内核的纯软件错误是不同的安全错误类别。

必须区别对待诸如熔毁(Meltdown)、Spectre、L1TF等硬件问题，因为它们通常会影响
所有操作系统（“OS”），因此需要在不同的OS供应商、发行版、硬件供应商和其他各方
之间进行协调。对于某些问题，软件缓解可能依赖于微码或固件更新，这需要进一步的
协调。

.. _zh_Contact:

接触
----

Linux内核硬件安全小组独立于普通的Linux内核安全小组。

该小组只负责协调被限制的硬件安全问题。Linux内核中纯软件安全漏洞的报告不由该
小组处理，报告者将被引导至常规Linux内核安全小组(:ref:`Documentation/admin-guide/
<securitybugs>`)联系。

可以通过电子邮件 <hardware-security@kernel.org> 与小组联系。这是一份私密的安全
官名单，他们将帮助您根据我们的文档化流程协调问题。

邮件列表是加密的，发送到列表的电子邮件可以通过PGP或S/MIME加密，并且必须使用报告
者的PGP密钥或S/MIME证书签名。该列表的PGP密钥和S/MIME证书可从
https://www.kernel.org/.... 获得。

虽然硬件安全问题通常由受影响的硬件供应商处理，但我们欢迎发现潜在硬件缺陷的研究
人员或个人与我们联系。

硬件安全官
^^^^^^^^^^

目前的硬件安全官小组:

  - Linus Torvalds（Linux基金会院士）
  - Greg Kroah Hartman（Linux基金会院士）
  - Thomas Gleixner（Linux基金会院士）

邮件列表的操作
^^^^^^^^^^^^^^

处理流程中使用的加密邮件列表托管在Linux Foundation的IT基础设施上。通过提供这项
服务，Linux基金会的IT基础设施安全总监在技术上有能力访问被限制的信息，但根据他
的雇佣合同，他必须保密。Linux基金会的IT基础设施安全总监还负责 kernel.org 基础
设施。

Linux基金会目前的IT基础设施安全总监是 Konstantin Ryabitsev。

保密协议
--------

Linux内核硬件安全小组不是正式的机构，因此无法签订任何保密协议。核心社区意识到
这些问题的敏感性，并提供了一份谅解备忘录。

谅解备忘录
----------

Linux内核社区深刻理解在不同操作系统供应商、发行商、硬件供应商和其他各方之间
进行协调时，保持硬件安全问题处于限制状态的要求。

Linux内核社区在过去已经成功地处理了硬件安全问题，并且有必要的机制允许在限制
限制下进行符合社区的开发。

Linux内核社区有一个专门的硬件安全小组负责初始联系，并监督在限制规则下处理
此类问题的过程。

硬件安全小组确定开发人员（领域专家），他们将组成特定问题的初始响应小组。最初
的响应小组可以引入更多的开发人员（领域专家）以最佳的技术方式解决这个问题。

所有相关开发商承诺遵守限制规定，并对收到的信息保密。违反承诺将导致立即从当前
问题中排除，并从所有相关邮件列表中删除。此外，硬件安全小组还将把违反者排除在
未来的问题之外。这一后果的影响在我们社区是一种非常有效的威慑。如果发生违规
情况，硬件安全小组将立即通知相关方。如果您或任何人发现潜在的违规行为，请立即
向硬件安全人员报告。

流程
^^^^

由于Linux内核开发的全球分布式特性，面对面的会议几乎不可能解决硬件安全问题。
由于时区和其他因素，电话会议很难协调，只能在绝对必要时使用。加密电子邮件已被
证明是解决此类问题的最有效和最安全的通信方法。

开始披露
""""""""

披露内容首先通过电子邮件联系Linux内核硬件安全小组。此初始联系人应包含问题的
描述和任何已知受影响硬件的列表。如果您的组织制造或分发受影响的硬件，我们建议
您也考虑哪些其他硬件可能会受到影响。

硬件安全小组将提供一个特定于事件的加密邮件列表，用于与报告者进行初步讨论、
进一步披露和协调。

硬件安全小组将向披露方提供一份开发人员（领域专家）名单，在与开发人员确认他们
将遵守本谅解备忘录和文件化流程后，应首先告知开发人员有关该问题的信息。这些开发
人员组成初始响应小组，并在初始接触后负责处理问题。硬件安全小组支持响应小组，
但不一定参与缓解开发过程。

虽然个别开发人员可能通过其雇主受到保密协议的保护，但他们不能以Linux内核开发
人员的身份签订个别保密协议。但是，他们将同意遵守这一书面程序和谅解备忘录。

披露方应提供已经或应该被告知该问题的所有其他实体的联系人名单。这有几个目的:

  - 披露的实体列表允许跨行业通信，例如其他操作系统供应商、硬件供应商等。

  - 可联系已披露的实体，指定应参与缓解措施开发的专家。

  - 如果需要处理某一问题的专家受雇于某一上市实体或某一上市实体的成员，则响应
    小组可要求该实体披露该专家。这确保专家也是实体反应小组的一部分。

披露
""""

披露方通过特定的加密邮件列表向初始响应小组提供详细信息。

根据我们的经验，这些问题的技术文档通常是一个足够的起点，最好通过电子邮件进行
进一步的技术澄清。

缓解开发
""""""""

初始响应小组设置加密邮件列表，或在适当的情况下重新修改现有邮件列表。

使用邮件列表接近于正常的Linux开发过程，并且在过去已经成功地用于为各种硬件安全
问题开发缓解措施。

邮件列表的操作方式与正常的Linux开发相同。发布、讨论和审查修补程序，如果同意，
则应用于非公共git存储库，参与开发人员只能通过安全连接访问该存储库。存储库包含
针对主线内核的主开发分支，并根据需要为稳定的内核版本提供向后移植分支。

最初的响应小组将根据需要从Linux内核开发人员社区中确定更多的专家。引进专家可以
在开发过程中的任何时候发生，需要及时处理。

如果专家受雇于披露方提供的披露清单上的实体或其成员，则相关实体将要求其参与。

否则，披露方将被告知专家参与的情况。谅解备忘录涵盖了专家，要求披露方确认参与。
如果披露方有令人信服的理由提出异议，则必须在五个工作日内提出异议，并立即与事件
小组解决。如果披露方在五个工作日内未作出回应，则视为默许。

在确认或解决异议后，专家由事件小组披露，并进入开发过程。

协调发布
""""""""

有关各方将协商限制结束的日期和时间。此时，准备好的缓解措施集成到相关的内核树中
并发布。

虽然我们理解硬件安全问题需要协调限制时间，但限制时间应限制在所有有关各方制定、
测试和准备缓解措施所需的最短时间内。人为地延长限制时间以满足会议讨论日期或其他
非技术原因，会给相关的开发人员和响应小组带来了更多的工作和负担，因为补丁需要
保持最新，以便跟踪正在进行的上游内核开发，这可能会造成冲突的更改。

CVE分配
"""""""

硬件安全小组和初始响应小组都不分配CVE，开发过程也不需要CVE。如果CVE是由披露方
提供的，则可用于文档中。

流程专使
--------

为了协助这一进程，我们在各组织设立了专使，他们可以回答有关报告流程和进一步处理
的问题或提供指导。专使不参与特定问题的披露，除非响应小组或相关披露方提出要求。
现任专使名单:

  ============= ========================================================
  ARM
  AMD		Tom Lendacky <thomas.lendacky@amd.com>
  IBM
  Intel		Tony Luck <tony.luck@intel.com>
  Qualcomm	Trilok Soni <tsoni@codeaurora.org>

  Microsoft	Sasha Levin <sashal@kernel.org>
  VMware
  Xen		Andrew Cooper <andrew.cooper3@citrix.com>

  Canonical	John Johansen <john.johansen@canonical.com>
  Debian	Ben Hutchings <ben@decadent.org.uk>
  Oracle	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
  Red Hat	Josh Poimboeuf <jpoimboe@redhat.com>
  SUSE		Jiri Kosina <jkosina@suse.cz>

  Amazon
  Google	Kees Cook <keescook@chromium.org>
  ============= ========================================================

如果要将您的组织添加到专使名单中，请与硬件安全小组联系。被提名的专使必须完全
理解和支持我们的过程，并且在Linux内核社区中很容易联系。

加密邮件列表
------------

我们使用加密邮件列表进行通信。这些列表的工作原理是，发送到列表的电子邮件使用
列表的PGP密钥或列表的/MIME证书进行加密。邮件列表软件对电子邮件进行解密，并
使用订阅者的PGP密钥或S/MIME证书为每个订阅者分别对其进行重新加密。有关邮件列表
软件和用于确保列表安全和数据保护的设置的详细信息，请访问:
https://www.kernel.org/....

关键点
^^^^^^

初次接触见 :ref:`zh_Contact`. 对于特定于事件的邮件列表，密钥和S/MIME证书通过
特定列表发送的电子邮件传递给订阅者。

订阅事件特定列表
^^^^^^^^^^^^^^^^

订阅由响应小组处理。希望参与通信的披露方将潜在订户的列表发送给响应组，以便
响应组可以验证订阅请求。

每个订户都需要通过电子邮件向响应小组发送订阅请求。电子邮件必须使用订阅服务器
的PGP密钥或S/MIME证书签名。如果使用PGP密钥，则必须从公钥服务器获得该密钥，
并且理想情况下该密钥连接到Linux内核的PGP信任网。另请参见:
https://www.kernel.org/signature.html.

响应小组验证订阅者，并将订阅者添加到列表中。订阅后，订阅者将收到来自邮件列表
的电子邮件，该邮件列表使用列表的PGP密钥或列表的/MIME证书签名。订阅者的电子邮件
客户端可以从签名中提取PGP密钥或S/MIME证书，以便订阅者可以向列表发送加密电子
邮件。


code:
.. _cn_process_howto:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/howto.rst <process_howto>`

译者::

    英文版维护者： Greg Kroah-Hartman <greg@kroah.com>
    中文版维护者： 李阳  Li Yang <leoyang.li@nxp.com>
    中文版翻译者： 李阳  Li Yang <leoyang.li@nxp.com>
                   时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
    中文版校译者:
                   钟宇  TripleX Chung <xxx.phy@gmail.com>
                   陈琦  Maggie Chen <chenqi@beyondsoft.com>
                   王聪  Wang Cong <xiyou.wangcong@gmail.com>

如何参与Linux内核开发
=====================

这是一篇将如何参与Linux内核开发的相关问题一网打尽的终极秘笈。它将指导你
成为一名Linux内核开发者，并且学会如何同Linux内核开发社区合作。它尽可能不
包括任何关于内核编程的技术细节，但会给你指引一条获得这些知识的正确途径。

如果这篇文章中的任何内容不再适用，请给文末列出的文件维护者发送补丁。

入门
----

你想了解如何成为一名Linux内核开发者？或者老板吩咐你“给这个设备写个Linux
驱动程序”？这篇文章的目的就是教会你达成这些目标的全部诀窍，它将描述你需
要经过的流程以及给出如何同内核社区合作的一些提示。它还将试图解释内核社区
为何这样运作。

Linux内核大部分是由C语言写成的，一些体系结构相关的代码用到了汇编语言。要
参与内核开发，你必须精通C语言。除非你想为某个架构开发底层代码，否则你并
不需要了解（任何体系结构的）汇编语言。下面列举的书籍虽然不能替代扎实的C
语言教育和多年的开发经验，但如果需要的话，做为参考还是不错的：

 - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
   《C程序设计语言（第2版·新版）》（徐宝文 李志 译）[机械工业出版社]
 - "Practical C Programming" by Steve Oualline [O'Reilly]
   《实用C语言编程（第三版）》（郭大海 译）[中国电力出版社]
 - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
   《C语言参考手册（原书第5版）》（邱仲潘 等译）[机械工业出版社]

Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C11标准，但也用到了一些
标准中没有定义的扩展。内核是自给自足的C环境，不依赖于标准C库的支持，所以
并不支持C标准中的部分定义。比如long long类型的大数除法和浮点运算就不允许
使用。有时候确实很难弄清楚内核对工具链的要求和它所使用的扩展，不幸的是目
前还没有明确的参考资料可以解释它们。请查阅gcc信息页（使用“info gcc”命令
显示）获得一些这方面信息。

请记住你是在学习怎么和已经存在的开发社区打交道。它由一群形形色色的人组成，
他们对代码、风格和过程有着很高的标准。这些标准是在长期实践中总结出来的，
适应于地理上分散的大型开发团队。它们已经被很好得整理成档，建议你在开发
之前尽可能多的学习这些标准，而不要期望别人来适应你或者你公司的行为方式。

法律问题
--------

Linux内核源代码都是在GPL（通用公共许可证）的保护下发布的。要了解这种许可
的细节请查看源代码主目录下的COPYING文件。Linux内核许可准则和如何使用
`SPDX <https://spdx.org/>` 标志符说明在这个文件中
:ref:`Documentation/translations/zh_CN/process/license-rules.rst <cn_kernel_licensing>`
如果你对它还有更深入问题请联系律师，而不要在Linux内核邮件组上提问。因为
邮件组里的人并不是律师，不要期望他们的话有法律效力。

对于GPL的常见问题和解答，请访问以下链接：
	https://www.gnu.org/licenses/gpl-faq.html

文档
----

Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着
不可估量的价值。当一个新的功能被加入内核，最好把解释如何使用这个功能的文
档也放进内核。当内核的改动导致面向用户空间的接口发生变化时，最好将相关信
息或手册页(manpages)的补丁发到mtk.manpages@gmail.com，以向手册页(manpages)
的维护者解释这些变化。

以下是内核代码中需要阅读的文档：
  :ref:`Documentation/admin-guide/README.rst <readme>`
    文件简要介绍了Linux内核的背景，并且描述了如何配置和编译内核。内核的
    新用户应该从这里开始。

  :ref:`Documentation/process/changes.rst <changes>`
    文件给出了用来编译和使用内核所需要的最小软件包列表。

  :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
    描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
    范。大多数维护者只会接收符合规定的补丁，很多人也只会帮忙检查符合风格
    的代码。

  :ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`

    这两份文档明确描述如何创建和发送补丁，其中包括（但不仅限于)：
       - 邮件内容
       - 邮件格式
       - 选择收件人

    遵守这些规定并不能保证提交成功（因为所有补丁需要通过严格的内容和风格
    审查），但是忽视他们几乎就意味着失败。

    其他关于如何正确地生成补丁的优秀文档包括：
    "The Perfect Patch"

        https://www.ozlabs.org/~akpm/stuff/tpp.txt

    "Linux kernel patch submission format"

        https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html

  :ref:`Documentation/translations/zh_CN/process/stable-api-nonsense.rst <cn_stable_api_nonsense>`
    论证内核为什么特意不包括稳定的内核内部API，也就是说不包括像这样的特
    性：

       - 子系统中间层（为了兼容性？）
       - 在不同操作系统间易于移植的驱动程序
       - 减缓（甚至阻止）内核代码的快速变化

    这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
    统转移到Linux的人来说也很重要。

  :ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
    如果你认为自己发现了Linux内核的安全性问题，请根据这篇文档中的步骤来
    提醒其他内核开发者并帮助解决这个问题。

  :ref:`Documentation/translations/zh_CN/process/management-style.rst <cn_managementstyle>`

    描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发（或者对
    它感到好奇）的人来说很重要，因为它解释了很多对于内核维护者独特行为的
    普遍误解与迷惑。

  :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
    解释了稳定版内核发布的规则，以及如何将改动放入这些版本的步骤。

  :ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
    有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
    的内容，可以查看这些文档。

  :ref:`Documentation/process/applying-patches.rst <applying_patches>`
    关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍

内核还拥有大量从代码自动生成或者从 ReStructuredText(ReST) 标记生成的文档，
比如这个文档，它包含内核内部API的全面介绍以及如何妥善处理加锁的规则。所有
这些文档都可以通过运行以下命令从内核代码中生成为PDF或HTML文档::

    make pdfdocs
    make htmldocs

ReST格式的文档会生成在 Documentation/output. 目录中。
它们也可以用下列命令生成 LaTeX 和 ePub 格式文档::

    make latexdocs
    make epubdocs

如何成为内核开发者
------------------
如果你对Linux内核开发一无所知，你应该访问“Linux内核新手”计划：

	https://kernelnewbies.org

它拥有一个可以问各种最基本的内核开发问题的邮件列表（在提问之前一定要记得
查找已往的邮件，确认是否有人已经回答过相同的问题）。它还拥有一个可以获得
实时反馈的IRC聊天频道，以及大量对于学习Linux内核开发相当有帮助的文档。

网站简要介绍了源代码组织结构、子系统划分以及目前正在进行的项目（包括内核
中的和单独维护的）。它还提供了一些基本的帮助信息，比如如何编译内核和打补
丁。

如果你想加入内核开发社区并协助完成一些任务，却找不到从哪里开始，可以访问
“Linux内核房管员”计划：

	https://kernelnewbies.org/KernelJanitors

这是极佳的起点。它提供一个相对简单的任务列表，列出内核代码中需要被重新
整理或者改正的地方。通过和负责这个计划的开发者们一同工作，你会学到将补丁
集成进内核的基本原理。如果还没有决定下一步要做什么的话，你还可能会得到方
向性的指点。

在真正动手修改内核代码之前，理解要修改的代码如何运作是必需的。要达到这个
目的，没什么办法比直接读代码更有效了（大多数花招都会有相应的注释），而且
一些特制的工具还可以提供帮助。例如，“Linux代码交叉引用”项目就是一个值得
特别推荐的帮助工具，它将源代码显示在有编目和索引的网页上。其中一个更新及
时的内核源码库，可以通过以下地址访问：

        https://elixir.bootlin.com/

开发流程
--------

目前Linux内核开发流程包括几个“主内核分支”和很多子系统相关的内核分支。这
些分支包括：

  - Linus 的内核源码树
  - 多个主要版本的稳定版内核树
  - 子系统相关的内核树
  - linux-next 集成测试树

主线树
------
主线树是由Linus Torvalds 维护的。你可以在https://kernel.org 网站或者代码
库中下找到它。它的开发遵循以下步骤：

  - 每当一个新版本的内核被发布，为期两周的集成窗口将被打开。在这段时间里
    维护者可以向Linus提交大段的修改，通常这些修改已经被放到-mm内核中几个
    星期了。提交大量修改的首选方式是使用git工具（内核的代码版本管理工具
    ，更多的信息可以在 https://git-scm.com/ 获取），不过使用普通补丁也是
    可以的。
  - 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
    新功能的补丁才可能被接受。请注意一个全新的驱动程序（或者文件系统）有
    可能在-rc1后被接受是因为这样的修改完全独立，不会影响其他的代码，所以
    没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁，不过所
    有的补丁需要同时被发送到相应的公众邮件列表以征询意见。
  - 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试
    时，一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
  - 这个过程一直持续下去直到内核被认为达到足够稳定的状态，持续时间大概是
    6个星期。

关于内核发布，值得一提的是Andrew Morton在linux-kernel邮件列表中如是说：
	“没有人知道新内核何时会被发布，因为发布是根据已知bug的情况来决定
	的，而不是根据一个事先制定好的时间表。”

子系统特定树
------------

各种内核子系统的维护者——以及许多内核子系统开发人员——在源代码库中公开了他们
当前的开发状态。这样，其他人就可以看到内核的不同区域发生了什么。在开发速度
很快的领域，可能会要求开发人员将提交的内容建立在这样的子系统内核树上，这样
就避免了提交与其他已经进行的工作之间的冲突。

这些存储库中的大多数都是Git树，但是也有其他的scm在使用，或者补丁队列被发布
为Quilt系列。这些子系统存储库的地址列在MAINTAINERS文件中。其中许多可以在
https://git.kernel.org/上浏览。

在将一个建议的补丁提交到这样的子系统树之前，需要对它进行审查，审查主要发生
在邮件列表上（请参见下面相应的部分）。对于几个内核子系统，这个审查过程是通
过工具补丁跟踪的。Patchwork提供了一个Web界面，显示补丁发布、对补丁的任何评
论或修订，维护人员可以将补丁标记为正在审查、接受或拒绝。大多数补丁网站都列
在 https://patchwork.kernel.org/

Linux-next 集成测试树
---------------------

在将子系统树的更新合并到主线树之前，需要对它们进行集成测试。为此，存在一个
特殊的测试存储库，其中几乎每天都会提取所有子系统树：

        https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git

通过这种方式，Linux-next 对下一个合并阶段将进入主线内核的内容给出了一个概要
展望。非常欢冒险的测试者运行测试Linux-next。

多个主要版本的稳定版内核树
-----------------------------------
由3个数字组成的内核版本号说明此内核是-stable版本。它们包含内核的相对较小且
至关重要的修补，这些修补针对安全性问题或者严重的内核退步。

这种版本的内核适用于那些期望获得最新的稳定版内核并且不想参与测试开发版或
者实验版的用户。

稳定版内核树版本由“稳定版”小组（邮件地址<stable@vger.kernel.org>）维护，一般
隔周发布新版本。

内核源码中的 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
文件具体描述了可被稳定版内核接受的修改类型以及发布的流程。

报告bug
-------

bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。我们鼓励用
户在这个工具中报告找到的所有bug。如何使用内核bugzilla的细节请访问：

	http://test.kernel.org/bugzilla/faq.html

内核源码主目录中的:ref:`admin-guide/reporting-bugs.rst <reportingbugs>`
文件里有一个很好的模板。它指导用户如何报告可能的内核bug以及需要提供哪些信息
来帮助内核开发者们找到问题的根源。

利用bug报告
-----------

练习内核开发技能的最好办法就是修改其他人报告的bug。你不光可以帮助内核变
得更加稳定，还可以学会如何解决实际问题从而提高自己的技能，并且让其他开发
者感受到你的存在。修改bug是赢得其他开发者赞誉的最好办法，因为并不是很多
人都喜欢浪费时间去修改别人报告的bug。

要尝试修改已知的bug，请访问 http://bugzilla.kernel.org 网址。

邮件列表
--------

正如上面的文档所描述，大多数的骨干内核开发者都加入了Linux Kernel邮件列
表。如何订阅和退订列表的细节可以在这里找到：

	http://vger.kernel.org/vger-lists.html#linux-kernel

网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些
存档。比如：

	https://lore.kernel.org/lkml/

在发信之前，我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细
讨论过的问题只在邮件列表的存档中可以找到。

大多数内核子系统也有自己独立的邮件列表来协调各自的开发工作。从
MAINTAINERS文件中可以找到不同话题对应的邮件列表。

很多邮件列表架设在kernel.org服务器上。这些列表的信息可以在这里找到：

	http://vger.kernel.org/vger-lists.html

在使用这些邮件列表时，请记住保持良好的行为习惯。下面的链接提供了与这些列
表（或任何其它邮件列表）交流的一些简单规则，虽然内容有点滥竽充数。

	http://www.albion.com/netiquette/

当有很多人回复你的邮件时，邮件的抄送列表会变得很长。请不要将任何人从抄送
列表中删除，除非你有足够的理由这么做。也不要只回复到邮件列表。请习惯于同
一封邮件接收两次（一封来自发送者一封来自邮件列表），而不要试图通过添加一
些奇特的邮件头来解决这个问题，人们不会喜欢的。

记住保留你所回复内容的上下文和源头。在你回复邮件的顶部保留“某某某说到……”
这几行。将你的评论加在被引用的段落之间而不要放在邮件的顶部。

如果你在邮件中附带补丁，请确认它们是可以直接阅读的纯文本（如
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
文档中所述）。内核开发者们不希望遇到附件或者被压缩了的补丁。只有这样才能
保证他们可以直接评论你的每行代码。请确保你使用的邮件发送程序不会修改空格
和制表符。一个防范性的测试方法是先将邮件发送给自己，然后自己尝试是否可以
顺利地打上收到的补丁。如果测试不成功，请调整或者更换你的邮件发送程序直到
它正确工作为止。

总而言之，请尊重其他的邮件列表订阅者。

同内核社区合作
----------------

内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的
时候，它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢？

  - 批评
  - 评论
  - 要求修改
  - 要求证明修改的必要性
  - 沉默

要记住，这些是把补丁放进内核的正常情况。你必须学会听取对补丁的批评和评论，
从技术层面评估它们，然后要么重写你的补丁要么简明扼要地论证修改是不必要
的。如果你发的邮件没有得到任何回应，请过几天后再试一次，因为有时信件会湮
没在茫茫信海中。

你不应该做的事情：

  - 期望自己的补丁不受任何质疑就直接被接受
  - 翻脸
  - 忽略别人的评论
  - 没有按照别人的要求做任何修改就重新提交

在一个努力追寻最好技术方案的社区里，对于一个补丁有多少好处总会有不同的见
解。你必须要抱着合作的态度，愿意改变自己的观点来适应内核的风格。或者至少
愿意去证明你的想法是有价值的。记住，犯错误是允许的，只要你愿意朝着正确的
方案去努力。

如果你的第一个补丁换来的是一堆修改建议，这是很正常的。这并不代表你的补丁
不会被接受，也不意味着有人和你作对。你只需要改正所有提出的问题然后重新发
送你的补丁。

内核社区和公司文化的差异
------------------------

内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
子，可以帮助你避免某些可能发生问题：
用这些话介绍你的修改提案会有好处：（在任何时候你都不应该用中文写提案）

    - 它同时解决了多个问题
    - 它删除了2000行代码
    - 这是补丁，它已经解释了我想要说明的
    - 我在5种不同的体系结构上测试过它……
    - 这是一系列小补丁用来……
    - 这个修改提高了普通机器的性能……

应该避免如下的说法：

    - 我们在AIX/ptx/Solaris就是这么做的，所以这么做肯定是好的……
    - 我做这行已经20年了，所以……
    - 为了我们公司赚钱考虑必须这么做
    - 这是我们的企业产品线所需要的
    - 这里是描述我观点的1000页设计文档
    - 这是一个5000行的补丁用来……
    - 我重写了现在乱七八糟的代码，这就是……
    - 我被规定了最后期限，所以这个补丁需要立刻被接受

另外一个内核社区与大部分传统公司的软件开发队伍不同的地方是无法面对面地交
流。使用电子邮件和IRC聊天工具做为主要沟通工具的一个好处是性别和种族歧视
将会更少。Linux内核的工作环境更能接受妇女和少数族群，因为每个人在别人眼
里只是一个邮件地址。国际化也帮助了公平的实现，因为你无法通过姓名来判断人
的性别。男人有可能叫李丽，女人也有可能叫王刚。大多数在Linux内核上工作过
并表达过看法的女性对在linux上工作的经历都给出了正面的评价。

对于一些不习惯使用英语的人来说，语言可能是一个引起问题的障碍。在邮件列表
中要正确地表达想法必需良好地掌握语言，所以建议你在发送邮件之前最好检查一
下英文写得是否正确。

拆分修改
--------

Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当地介绍、讨论并且
拆分成独立的小段。这几乎完全和公司中的习惯背道而驰。你的想法应该在开发最
开始的阶段就让大家知道，这样你就可以及时获得对你正在进行的开发的反馈。这
样也会让社区觉得你是在和他们协作，而不是仅仅把他们当作倾销新功能的对象。
无论如何，你不要一次性地向邮件列表发送50封信，你的补丁序列应该永远用不到
这么多。

将补丁拆开的原因如下：

1) 小的补丁更有可能被接受，因为它们不需要太多的时间和精力去验证其正确性。
   一个5行的补丁，可能在维护者看了一眼以后就会被接受。而500行的补丁则
   需要数个小时来审查其正确性（所需时间随补丁大小增加大约呈指数级增长）。

   当出了问题的时候，小的补丁也会让调试变得非常容易。一个一个补丁地回溯
   将会比仔细剖析一个被打上的大补丁（这个补丁破坏了其他东西）容易得多。

2）不光发送小的补丁很重要，在提交之前重新编排、化简（或者仅仅重新排列）
   补丁也是很重要的。

这里有内核开发者Al Viro打的一个比方：
	“想象一个老师正在给学生批改数学作业。老师并不希望看到学生为了得
	到正确解法所进行的尝试和产生的错误。他希望看到的是最干净最优雅的
	解答。好学生了解这点，绝不会把最终解决之前的中间方案提交上去。”

	内核开发也是这样。维护者和评审者不希望看到一个人在解决问题时的思
	考过程。他们只希望看到简单和优雅的解决方案。

直接给出一流的解决方案，和社区一起协作讨论尚未完成的工作，这两者之间似乎
很难找到一个平衡点。所以最好尽早开始收集有利于你进行改进的反馈；同时也要
保证修改分成很多小块，这样在整个项目都准备好被包含进内核之前，其中的一部
分可能会先被接收。

你必须明白这么做是无法令人接受的：试图将不完整的代码提交进内核，然后再找
时间修复。

证明修改的必要性
----------------
除了将补丁拆成小块，很重要的一点是让Linux社区了解他们为什么需要这样修改。
你必须证明新功能是有人需要的并且是有用的。

记录修改
--------

当你发送补丁的时候，需要特别留意邮件正文的内容。因为这里的信息将会做为补
丁的修改记录(ChangeLog)，会被一直保留以备大家查阅。它需要完全地描述补丁，
包括：

  - 为什么需要这个修改
  - 补丁的总体设计
  - 实现细节
  - 测试结果

想了解它具体应该看起来像什么，请查阅以下文档中的“ChangeLog”章节：
  “The Perfect Patch”
  	 https://www.ozlabs.org/~akpm/stuff/tpp.txt

这些事情有时候做起来很难。想要在任何方面都做到完美可能需要好几年时间。这
是一个持续提高的过程，它需要大量的耐心和决心。只要不放弃，你一定可以做到。
很多人已经做到了，而他们都曾经和现在的你站在同样的起点上。

感谢
----
感谢Paolo Ciarrocchi允许“开发流程”部分基于他所写的文章
(http://www.kerneltravel.net/newbie/2.6-development_process)，感谢Randy
Dunlap和Gerrit Huizenga完善了应该说和不该说的列表。感谢Pat Mochel, Hanna
Linder, Randy Dunlap, Kay Sievers, Vojtech Pavlik, Jan Kara, Josh Boyer,
Kees Cook, Andrew Morton, Andi Kleen, Vadim Lobanov, Jesper Juhl, Adrian
Bunk, Keri Harris, Frans Pop, David A. Wheeler, Junio Hamano, Michael
Kerrisk和Alex Shepard的评审、建议和贡献。没有他们的帮助，这篇文档是不可
能完成的。

英文版维护者： Greg Kroah-Hartman <greg@kroah.com>


code:
.. raw:: latex

	\renewcommand\thesection*
	\renewcommand\thesubsection*

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/index.rst <process_index>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

.. _cn_process_index:

========================
与Linux 内核社区一起工作
========================

你想成为Linux内核开发人员吗？欢迎之至！在学习许多关于内核的技术知识的同时，
了解我们社区的工作方式也很重要。阅读这些文档可以让您以更轻松的、麻烦更少的
方式将更改合并到内核。

以下是每位开发人员都应阅读的基本指南：

.. toctree::
   :maxdepth: 1

   howto
   code-of-conduct
   code-of-conduct-interpretation
   submitting-patches
   programming-language
   coding-style
   development-process
   email-clients
   license-rules
   kernel-enforcement-statement
   kernel-driver-statement

其它大多数开发人员感兴趣的社区指南：

.. toctree::
   :maxdepth: 1

   submit-checklist
   stable-api-nonsense
   stable-kernel-rules
   management-style
   embargoed-hardware-issues

这些是一些总体性技术指南，由于不大好分类而放在这里：

.. toctree::
   :maxdepth: 1

   magic-number
   volatile-considered-harmful

.. only::  subproject and html

   目录
   ====

   * :ref:`genindex`


code:
.. _cn_process_statement_driver:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/kernel-driver-statement.rst <process_statement_driver>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

内核驱动声明
------------

关于Linux内核模块的立场声明
===========================

我们，以下署名的Linux内核开发人员，认为任何封闭源Linux内核模块或驱动程序都是
有害的和不可取的。我们已经一再发现它们对Linux用户，企业和更大的Linux生态系统
有害。这样的模块否定了Linux开发模型的开放性，稳定性，灵活性和可维护性，并使
他们的用户无法使用Linux社区的专业知识。提供闭源内核模块的供应商迫使其客户
放弃Linux的主要优势或选择新的供应商。因此，为了充分利用开源所提供的成本节省和
共享支持优势，我们敦促供应商采取措施，以开源内核代码在Linux上为其客户提供支持。

我们只为自己说话，而不是我们今天可能会为之工作，过去或将来会为之工作的任何公司。

 - Dave Airlie
 - Nick Andrew
 - Jens Axboe
 - Ralf Baechle
 - Felipe Balbi
 - Ohad Ben-Cohen
 - Muli Ben-Yehuda
 - Jiri Benc
 - Arnd Bergmann
 - Thomas Bogendoerfer
 - Vitaly Bordug
 - James Bottomley
 - Josh Boyer
 - Neil Brown
 - Mark Brown
 - David Brownell
 - Michael Buesch
 - Franck Bui-Huu
 - Adrian Bunk
 - François Cami
 - Ralph Campbell
 - Luiz Fernando N. Capitulino
 - Mauro Carvalho Chehab
 - Denis Cheng
 - Jonathan Corbet
 - Glauber Costa
 - Alan Cox
 - Magnus Damm
 - Ahmed S. Darwish
 - Robert P. J. Day
 - Hans de Goede
 - Arnaldo Carvalho de Melo
 - Helge Deller
 - Jean Delvare
 - Mathieu Desnoyers
 - Sven-Thorsten Dietrich
 - Alexey Dobriyan
 - Daniel Drake
 - Alex Dubov
 - Randy Dunlap
 - Michael Ellerman
 - Pekka Enberg
 - Jan Engelhardt
 - Mark Fasheh
 - J. Bruce Fields
 - Larry Finger
 - Jeremy Fitzhardinge
 - Mike Frysinger
 - Kumar Gala
 - Robin Getz
 - Liam Girdwood
 - Jan-Benedict Glaw
 - Thomas Gleixner
 - Brice Goglin
 - Cyrill Gorcunov
 - Andy Gospodarek
 - Thomas Graf
 - Krzysztof Halasa
 - Harvey Harrison
 - Stephen Hemminger
 - Michael Hennerich
 - Tejun Heo
 - Benjamin Herrenschmidt
 - Kristian Høgsberg
 - Henrique de Moraes Holschuh
 - Marcel Holtmann
 - Mike Isely
 - Takashi Iwai
 - Olof Johansson
 - Dave Jones
 - Jesper Juhl
 - Matthias Kaehlcke
 - Kenji Kaneshige
 - Jan Kara
 - Jeremy Kerr
 - Russell King
 - Olaf Kirch
 - Roel Kluin
 - Hans-Jürgen Koch
 - Auke Kok
 - Peter Korsgaard
 - Jiri Kosina
 - Aaro Koskinen
 - Mariusz Kozlowski
 - Greg Kroah-Hartman
 - Michael Krufky
 - Aneesh Kumar
 - Clemens Ladisch
 - Christoph Lameter
 - Gunnar Larisch
 - Anders Larsen
 - Grant Likely
 - John W. Linville
 - Yinghai Lu
 - Tony Luck
 - Pavel Machek
 - Matt Mackall
 - Paul Mackerras
 - Roland McGrath
 - Patrick McHardy
 - Kyle McMartin
 - Paul Menage
 - Thierry Merle
 - Eric Miao
 - Akinobu Mita
 - Ingo Molnar
 - James Morris
 - Andrew Morton
 - Paul Mundt
 - Oleg Nesterov
 - Luca Olivetti
 - S.Çağlar Onur
 - Pierre Ossman
 - Keith Owens
 - Venkatesh Pallipadi
 - Nick Piggin
 - Nicolas Pitre
 - Evgeniy Polyakov
 - Richard Purdie
 - Mike Rapoport
 - Sam Ravnborg
 - Gerrit Renker
 - Stefan Richter
 - David Rientjes
 - Luis R. Rodriguez
 - Stefan Roese
 - Francois Romieu
 - Rami Rosen
 - Stephen Rothwell
 - Maciej W. Rozycki
 - Mark Salyzyn
 - Yoshinori Sato
 - Deepak Saxena
 - Holger Schurig
 - Amit Shah
 - Yoshihiro Shimoda
 - Sergei Shtylyov
 - Kay Sievers
 - Sebastian Siewior
 - Rik Snel
 - Jes Sorensen
 - Alexey Starikovskiy
 - Alan Stern
 - Timur Tabi
 - Hirokazu Takata
 - Eliezer Tamir
 - Eugene Teo
 - Doug Thompson
 - FUJITA Tomonori
 - Dmitry Torokhov
 - Marcelo Tosatti
 - Steven Toth
 - Theodore Tso
 - Matthias Urlichs
 - Geert Uytterhoeven
 - Arjan van de Ven
 - Ivo van Doorn
 - Rik van Riel
 - Wim Van Sebroeck
 - Hans Verkuil
 - Horst H. von Brand
 - Dmitri Vorobiev
 - Anton Vorontsov
 - Daniel Walker
 - Johannes Weiner
 - Harald Welte
 - Matthew Wilcox
 - Dan J. Williams
 - Darrick J. Wong
 - David Woodhouse
 - Chris Wright
 - Bryan Wu
 - Rafael J. Wysocki
 - Herbert Xu
 - Vlad Yasevich
 - Peter Zijlstra
 - Bartlomiej Zolnierkiewicz


code:
.. _cn_process_statement_kernel:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

Linux 内核执行声明
------------------

作为Linux内核的开发人员，我们对如何使用我们的软件以及如何实施软件许可证有着
浓厚的兴趣。遵守GPL-2.0的互惠共享义务对我们软件和社区的长期可持续性至关重要。

虽然有权强制执行对我们社区的贡献中的单独版权权益，但我们有共同的利益，即确保
个人强制执行行动的方式有利于我们的社区，不会对我们软件生态系统的健康和增长
产生意外的负面影响。为了阻止无益的执法行动，我们同意代表我们自己和我们版权
利益的任何继承人对Linux内核用户作出以下符合我们开发社区最大利益的承诺:

    尽管有GPL-2.0的终止条款，我们同意，采用以下GPL-3.0条款作为我们许可证下的
    附加许可，作为任何对许可证下权利的非防御性主张，这符合我们开发社区的最佳
    利益。

        但是，如果您停止所有违反本许可证的行为，则您从特定版权持有人处获得的
        许可证将被恢复：（a）暂时恢复，除非版权持有人明确并最终终止您的许可证；
        以及（b）永久恢复, 如果版权持有人未能在你终止违反后60天内以合理方式
        通知您违反本许可证的行为，则永久恢复您的许可证。

        此外，如果版权所有者以某种合理的方式通知您违反了本许可，这是您第一次
        从该版权所有者处收到违反本许可的通知（对于任何作品），并且您在收到通知
        后的30天内纠正违规行为。则您从特定版权所有者处获得的许可将永久恢复.

我们提供这些保证的目的是鼓励更多地使用该软件。我们希望公司和个人使用、修改和
分发此软件。我们希望以公开和透明的方式与用户合作，以消除我们对法规遵从性或强制
执行的任何不确定性，这些不确定性可能会限制我们软件的采用。我们将法律行动视为
最后手段，只有在其他社区努力未能解决这一问题时才采取行动。

最后，一旦一个不合规问题得到解决，我们希望用户会感到欢迎，加入我们为之努力的
这个项目。共同努力，我们会更强大。

除了下面提到的以外，我们只为自己说话，而不是为今天、过去或将来可能为之工作的
任何公司说话。

  - Laura Abbott
  - Bjorn Andersson (Linaro)
  - Andrea Arcangeli
  - Neil Armstrong
  - Jens Axboe
  - Pablo Neira Ayuso
  - Khalid Aziz
  - Ralf Baechle
  - Felipe Balbi
  - Arnd Bergmann
  - Ard Biesheuvel
  - Tim Bird
  - Paolo Bonzini
  - Christian Borntraeger
  - Mark Brown (Linaro)
  - Paul Burton
  - Javier Martinez Canillas
  - Rob Clark
  - Kees Cook (Google)
  - Jonathan Corbet
  - Dennis Dalessandro
  - Vivien Didelot (Savoir-faire Linux)
  - Hans de Goede
  - Mel Gorman (SUSE)
  - Sven Eckelmann
  - Alex Elder (Linaro)
  - Fabio Estevam
  - Larry Finger
  - Bhumika Goyal
  - Andy Gross
  - Juergen Gross
  - Shawn Guo
  - Ulf Hansson
  - Stephen Hemminger (Microsoft)
  - Tejun Heo
  - Rob Herring
  - Masami Hiramatsu
  - Michal Hocko
  - Simon Horman
  - Johan Hovold (Hovold Consulting AB)
  - Christophe JAILLET
  - Olof Johansson
  - Lee Jones (Linaro)
  - Heiner Kallweit
  - Srinivas Kandagatla
  - Jan Kara
  - Shuah Khan (Samsung)
  - David Kershner
  - Jaegeuk Kim
  - Namhyung Kim
  - Colin Ian King
  - Jeff Kirsher
  - Greg Kroah-Hartman (Linux Foundation)
  - Christian König
  - Vinod Koul
  - Krzysztof Kozlowski
  - Viresh Kumar
  - Aneesh Kumar K.V
  - Julia Lawall
  - Doug Ledford
  - Chuck Lever (Oracle)
  - Daniel Lezcano
  - Shaohua Li
  - Xin Long
  - Tony Luck
  - Catalin Marinas (Arm Ltd)
  - Mike Marshall
  - Chris Mason
  - Paul E. McKenney
  - Arnaldo Carvalho de Melo
  - David S. Miller
  - Ingo Molnar
  - Kuninori Morimoto
  - Trond Myklebust
  - Martin K. Petersen (Oracle)
  - Borislav Petkov
  - Jiri Pirko
  - Josh Poimboeuf
  - Sebastian Reichel (Collabora)
  - Guenter Roeck
  - Joerg Roedel
  - Leon Romanovsky
  - Steven Rostedt (VMware)
  - Frank Rowand
  - Ivan Safonov
  - Anna Schumaker
  - Jes Sorensen
  - K.Y. Srinivasan
  - David Sterba (SUSE)
  - Heiko Stuebner
  - Jiri Kosina (SUSE)
  - Willy Tarreau
  - Dmitry Torokhov
  - Linus Torvalds
  - Thierry Reding
  - Rik van Riel
  - Luis R. Rodriguez
  - Geert Uytterhoeven (Glider bvba)
  - Eduardo Valentin (Amazon.com)
  - Daniel Vetter
  - Linus Walleij
  - Richard Weinberger
  - Dan Williams
  - Rafael J. Wysocki
  - Arvind Yadav
  - Masahiro Yamada
  - Wei Yongjun
  - Lv Zheng
  - Marc Zyngier (Arm Ltd)


code:
.. SPDX-License-Identifier: GPL-2.0

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/license-rules.rst <kernel_licensing>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

.. _cn_kernel_licensing:

Linux内核许可规则
=================

Linux内核根据LICENSES/preferred/GPL-2.0中提供的GNU通用公共许可证版本2
（GPL-2.0）的条款提供，并在LICENSES/exceptions/Linux-syscall-note中显式
描述了例外的系统调用，如COPYING文件中所述。

此文档文件提供了如何对每个源文件进行注释以使其许可证清晰明确的说明。
它不会取代内核的许可证。

内核源代码作为一个整体适用于COPYING文件中描述的许可证，但是单个源文件可以
具有不同的与GPL-20兼容的许可证::

    GPL-1.0+ : GNU通用公共许可证v1.0或更高版本
    GPL-2.0+ : GNU通用公共许可证v2.0或更高版本
    LGPL-2.0 : 仅限GNU库通用公共许可证v2
    LGPL-2.0+: GNU 库通用公共许可证v2或更高版本
    LGPL-2.1 : 仅限GNU宽通用公共许可证v2.1
    LGPL-2.1+: GNU宽通用公共许可证v2.1或更高版本

除此之外，个人文件可以在双重许可下提供，例如一个兼容的GPL变体，或者BSD，
MIT等许可。

用户空间API（UAPI）头文件描述了用户空间程序与内核的接口，这是一种特殊情况。
根据内核COPYING文件中的注释，syscall接口是一个明确的边界，它不会将GPL要求
扩展到任何使用它与内核通信的软件。由于UAPI头文件必须包含在创建在Linux内核
上运行的可执行文件的任何源文件中，因此此例外必须记录在特别的许可证表述中。

表达源文件许可证的常用方法是将匹配的样板文本添加到文件的顶部注释中。由于
格式，拼写错误等，这些“样板”很难通过那些在上下文中使用的验证许可证合规性
的工具。

样板文本的替代方法是在每个源文件中使用软件包数据交换（SPDX）许可证标识符。
SPDX许可证标识符是机器可解析的，并且是用于提供文件内容的许可证的精确缩写。
SPDX许可证标识符由Linux 基金会的SPDX 工作组管理，并得到了整个行业，工具
供应商和法律团队的合作伙伴的一致同意。有关详细信息，请参阅
https://spdx.org/

Linux内核需要所有源文件中的精确SPDX标识符。内核中使用的有效标识符在
`许可标识符`_ 一节中进行了解释，并且已可以在
https://spdx.org/licenses/ 上的官方SPDX许可证列表中检索，并附带许可证
文本。

许可标识符语法
--------------

1.安置:

   内核文件中的SPDX许可证标识符应添加到可包含注释的文件中的第一行。对于大多
   数文件，这是第一行，除了那些在第一行中需要'#!PATH_TO_INTERPRETER'的脚本。
   对于这些脚本，SPDX标识符进入第二行。

|

2. 风格:

   SPDX许可证标识符以注释的形式添加。注释样式取决于文件类型::

      C source:	// SPDX-License-Identifier: <SPDX License Expression>
      C header:	/* SPDX-License-Identifier: <SPDX License Expression> */
      ASM:	/* SPDX-License-Identifier: <SPDX License Expression> */
      scripts:	# SPDX-License-Identifier: <SPDX License Expression>
      .rst:	.. SPDX-License-Identifier: <SPDX License Expression>
      .dts{i}:	// SPDX-License-Identifier: <SPDX License Expression>

   如果特定工具无法处理标准注释样式，则应使用工具接受的相应注释机制。这是在
   C 头文件中使用“/\*\*/”样式注释的原因。过去在使用生成的.lds文件中观察到
   构建被破坏，其中'ld'无法解析C++注释。现在已经解决了这个问题，但仍然有较
   旧的汇编程序工具无法处理C++样式的注释。

|

3. 句法:

   <SPDX许可证表达式>是SPDX许可证列表中的SPDX短格式许可证标识符，或者在许可
   证例外适用时由“WITH”分隔的两个SPDX短格式许可证标识符的组合。当应用多个许
   可证时，表达式由分隔子表达式的关键字“AND”，“OR”组成，并由“（”，“）”包围。

   带有“或更高”选项的[L]GPL等许可证的许可证标识符通过使用“+”来表示“或更高”
   选项来构建。::

      // SPDX-License-Identifier: GPL-2.0+
      // SPDX-License-Identifier: LGPL-2.1+

   当需要修正的许可证时，应使用WITH。 例如，linux内核UAPI文件使用表达式::

      // SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
      // SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note

   其它在内核中使用WITH例外的事例如下::

      // SPDX-License-Identifier: GPL-2.0 WITH mif-exception
      // SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0

   例外只能与特定的许可证标识符一起使用。有效的许可证标识符列在异常文本文件
   的标记中。有关详细信息，请参阅 `许可标识符`_ 一章中的 `例外`_ 。

   如果文件是双重许可且只选择一个许可证，则应使用OR。例如，一些dtsi文件在双
   许可下可用::

      // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause

   内核中双许可文件中许可表达式的示例::

      // SPDX-License-Identifier: GPL-2.0 OR MIT
      // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
      // SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
      // SPDX-License-Identifier: GPL-2.0 OR MPL-1.1
      // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT
      // SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL

   如果文件具有多个许可证，其条款全部适用于使用该文件，则应使用AND。例如，
   如果代码是从另一个项目继承的，并且已经授予了将其放入内核的权限，但原始
   许可条款需要保持有效::

      // SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT

   另一个需要遵守两套许可条款的例子是::

      // SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+

许可标识符
----------

当前使用的许可证以及添加到内核的代码许可证可以分解为：

1. _`优先许可`:

   应尽可能使用这些许可证，因为它们已知完全兼容并广泛使用。这些许可证在内核
   目录::

      LICENSES/preferred/

   此目录中的文件包含完整的许可证文本和 `元标记`_ 。文件名与SPDX许可证标识
   符相同，后者应用于源文件中的许可证。

   例如::

      LICENSES/preferred/GPL-2.0

   包含GPLv2许可证文本和所需的元标签::

      LICENSES/preferred/MIT

   包含MIT许可证文本和所需的元标记

   _`元标记`:

   许可证文件中必须包含以下元标记：

   - Valid-License-Identifier:

     一行或多行, 声明那些许可标识符在项目内有效, 以引用此特定许可的文本。通
     常这是一个有效的标识符，但是例如对于带有'或更高'选项的许可证，两个标识
     符都有效。

   - SPDX-URL:

     SPDX页面的URL，其中包含与许可证相关的其他信息.

   - Usage-Guidance:

     使用建议的自由格式文本。该文本必须包含SPDX许可证标识符的正确示例，因为
     它们应根据 `许可标识符语法`_ 指南放入源文件中。

   - License-Text:

     此标记之后的所有文本都被视为原始许可文本

   文件格式示例::

      Valid-License-Identifier: GPL-2.0
      Valid-License-Identifier: GPL-2.0+
      SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
      Usage-Guide:
        To use this license in source code, put one of the following SPDX
	tag/value pairs into a comment according to the placement
	guidelines in the licensing rules documentation.
	For 'GNU General Public License (GPL) version 2 only' use:
	  SPDX-License-Identifier: GPL-2.0
	For 'GNU General Public License (GPL) version 2 or any later version' use:
	  SPDX-License-Identifier: GPL-2.0+
      License-Text:
        Full license text

   ::

      SPDX-License-Identifier: MIT
      SPDX-URL: https://spdx.org/licenses/MIT.html
      Usage-Guide:
	To use this license in source code, put the following SPDX
	tag/value pair into a comment according to the placement
	guidelines in the licensing rules documentation.
	  SPDX-License-Identifier: MIT
      License-Text:
        Full license text

|

2. 不推荐的许可证:

   这些许可证只应用于现有代码或从其他项目导入代码。这些许可证在内核目录::

      LICENSES/other/

   此目录中的文件包含完整的许可证文本和 `元标记`_ 。文件名与SPDX许可证标识
   符相同，后者应用于源文件中的许可证。

   例如::

      LICENSES/other/ISC

   包含国际系统联合许可文本和所需的元标签::

      LICENSES/other/ZLib

   包含ZLIB许可文本和所需的元标签.

   元标签:

   “其他”许可证的元标签要求与 `优先许可`_ 的要求相同。

   文件格式示例::

      Valid-License-Identifier: ISC
      SPDX-URL: https://spdx.org/licenses/ISC.html
      Usage-Guide:
        Usage of this license in the kernel for new code is discouraged
	and it should solely be used for importing code from an already
	existing project.
        To use this license in source code, put the following SPDX
	tag/value pair into a comment according to the placement
	guidelines in the licensing rules documentation.
	  SPDX-License-Identifier: ISC
      License-Text:
        Full license text

|

3. _`例外`:

   某些许可证可以修改，并允许原始许可证不具有的某些例外权利。这些例外在
   内核目录::

      LICENSES/exceptions/

   此目录中的文件包含完整的例外文本和所需的 `例外元标记`_ 。

   例如::

      LICENSES/exceptions/Linux-syscall-note

   包含Linux内核的COPYING文件中记录的Linux系统调用例外，该文件用于UAPI
   头文件。例如::

      LICENSES/exceptions/GCC-exception-2.0

   包含GCC'链接例外'，它允许独立于其许可证的任何二进制文件与标记有此例外的
   文件的编译版本链接。这是从GPL不兼容源代码创建可运行的可执行文件所必需的。

   _`例外元标记`:

   以下元标记必须在例外文件中可用：

   - SPDX-Exception-Identifier:

     一个可与SPDX许可证标识符一起使用的例外标识符。

   - SPDX-URL:

     SPDX页面的URL，其中包含与例外相关的其他信息。

   - SPDX-Licenses:

     以逗号分隔的例外可用的SPDX许可证标识符列表。

   - Usage-Guidance:

     使用建议的自由格式文本。必须在文本后面加上SPDX许可证标识符的正确示例，
     因为它们应根据 `许可标识符语法`_ 指南放入源文件中。

   - Exception-Text:

     此标记之后的所有文本都被视为原始异常文本

   文件格式示例::

      SPDX-Exception-Identifier: Linux-syscall-note
      SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
      SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
      Usage-Guidance:
        This exception is used together with one of the above SPDX-Licenses
	to mark user-space API (uapi) header files so they can be included
	into non GPL compliant user-space application code.
        To use this exception add it with the keyword WITH to one of the
	identifiers in the SPDX-Licenses tag:
	  SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
      Exception-Text:
        Full exception text

   ::

      SPDX-Exception-Identifier: GCC-exception-2.0
      SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html
      SPDX-Licenses: GPL-2.0, GPL-2.0+
      Usage-Guidance:
        The "GCC Runtime Library exception 2.0" is used together with one
	of the above SPDX-Licenses for code imported from the GCC runtime
	library.
        To use this exception add it with the keyword WITH to one of the
	identifiers in the SPDX-Licenses tag:
	  SPDX-License-Identifier: <SPDX-License> WITH GCC-exception-2.0
      Exception-Text:
        Full exception text

所有SPDX许可证标识符和例外都必须在LICENSES子目录中具有相应的文件。这是允许
工具验证（例如checkpatch.pl）以及准备好从源读取和提取许可证所必需的, 这是
各种FOSS组织推荐的，例如 `FSFE REUSE initiative <https://reuse.software/>`_.

_`模块许可`
-----------------

   可加载内核模块还需要MODULE_LICENSE（）标记。此标记既不替代正确的源代码
   许可证信息（SPDX-License-Identifier），也不以任何方式表示或确定提供模块
   源代码的确切许可证。

   此标记的唯一目的是提供足够的信息，该模块是否是自由软件或者是内核模块加
   载器和用户空间工具的专有模块。

   MODULE_LICENSE（）的有效许可证字符串是:

    ============================= =============================================
    "GPL"			  模块是根据GPL版本2许可的。这并不表示仅限于
                                  GPL-2.0或GPL-2.0或更高版本之间的任何区别。
                                  最正确许可证信息只能通过相应源文件中的许可证
                                  信息来确定

    "GPL v2"			  和"GPL"相同，它的存在是因为历史原因。

    "GPL and additional rights"   表示模块源在GPL v2变体和MIT许可下双重许可的
                                  历史变体。请不要在新代码中使用。

    "Dual MIT/GPL"		  表达该模块在GPL v2变体或MIT许可证选择下双重
                                  许可的正确方式。

    "Dual BSD/GPL"		  该模块根据GPL v2变体或BSD许可证选择进行双重
                                  许可。 BSD许可证的确切变体只能通过相应源文件
                                  中的许可证信息来确定。

    "Dual MPL/GPL"		  该模块根据GPL v2变体或Mozilla Public License
                                  （MPL）选项进行双重许可。 MPL许可证的确切变体
                                  只能通过相应的源文件中的许可证信息来确定。

    "Proprietary"		  该模块属于专有许可。此字符串仅用于专有的第三
                                  方模块，不能用于在内核树中具有源代码的模块。
                                  以这种方式标记的模块在加载时会使用'P'标记污
                                  染内核，并且内核模块加载器拒绝将这些模块链接
                                  到使用EXPORT_SYMBOL_GPL（）导出的符号。
    ============================= =============================================


code:
.. _cn_magicnumbers:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`

如果想评论或更新本文的内容，请直接发信到LKML。如果你使用英文交流有困难的话，也可
以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题，请联系中文版维护者::

        中文版维护者： 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
        中文版翻译者： 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
        中文版校译者： 贾威威 Jia Wei Wei <harryxiyou@gmail.com>

Linux 魔术数
============

这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值，你也应该把这个魔术值添加到这个文件，因为我们最好把用于各种结构的魔术值统一起来。

使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击，或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码，例如，经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。

使用魔术值的方法是在结构的开始处声明的，如下::

        struct tty_ldisc {
	        int	magic;
        	...
        };

当你以后给内核添加增强功能的时候，请遵守这条规则！这样就会节省数不清的调试时间，特别是一些古怪的情况，例如，数组超出范围并且重新写了超出部分。遵守这个规则，这些情况可以被快速地，安全地避免。

		Theodore Ts'o
		  31 Mar 94

给当前的Linux 2.1.55添加魔术表。

		Michael Chastain
		<mailto:mec@shout.net>
		22 Sep 1997

现在应该最新的Linux 2.1.112.因为在特性冻结期间，不能在2.2.x前改变任何东西。这些条目被数域所排序。

		Krzysztof G.Baranowski
	        <mailto: kgb@knm.org.pl>
		29 Jul 1998

更新魔术表到Linux 2.5.45。刚好越过特性冻结，但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。

		Petr Baudis
		<pasky@ucw.cz>
		03 Nov 2002

更新魔术表到Linux 2.5.74。

		Fabian Frederick
                <ffrederick@users.sourceforge.net>
		09 Jul 2003

===================== ================ ======================== ==========================================
魔术数名              数字             结构                     文件
===================== ================ ======================== ==========================================
PG_MAGIC              'P'              pg_{read,write}_hdr      ``include/linux/pg.h``
APM_BIOS_MAGIC        0x4101           apm_user                 ``arch/x86/kernel/apm_32.c``
FASYNC_MAGIC          0x4601           fasync_struct            ``include/linux/fs.h``
SLIP_MAGIC            0x5302           slip                     ``drivers/net/slip.h``
MGSLPC_MAGIC          0x5402           mgslpc_info              ``drivers/char/pcmcia/synclink_cs.c``
BAYCOM_MAGIC          0x19730510       baycom_state             ``drivers/net/baycom_epp.c``
HDLCDRV_MAGIC         0x5ac6e778       hdlcdrv_state            ``include/linux/hdlcdrv.h``
KV_MAGIC              0x5f4b565f       kernel_vars_s            ``arch/mips/include/asm/sn/klkernvars.h``
CODA_MAGIC            0xC0DAC0DA       coda_file_info           ``fs/coda/coda_fs_i.h``
YAM_MAGIC             0xF10A7654       yam_port                 ``drivers/net/hamradio/yam.c``
CCB_MAGIC             0xf2691ad2       ccb                      ``drivers/scsi/ncr53c8xx.c``
QUEUE_MAGIC_FREE      0xf7e1c9a3       queue_entry              ``drivers/scsi/arm/queue.c``
QUEUE_MAGIC_USED      0xf7e1cc33       queue_entry              ``drivers/scsi/arm/queue.c``
NMI_MAGIC             0x48414d4d455201 nmi_s                    ``arch/mips/include/asm/sn/nmi.h``
===================== ================ ======================== ==========================================


code:
.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/management-style.rst <managementstyle>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

.. _cn_managementstyle:

Linux内核管理风格
=================

这是一个简短的文档，描述了Linux内核首选的（或胡编的，取决于您问谁）管理风格。
它的目的是在某种程度上参照 :ref:`process/coding-style.rst <codingstyle>`
主要是为了避免反复回答 [#cnf1]_ 相同（或类似）的问题。

管理风格是非常个人化的，比简单的编码风格规则更难以量化，因此本文档可能与实
际情况有关，也可能与实际情况无关。起初它是一个玩笑，但这并不意味着它可能不
是真的。你得自己决定。

顺便说一句，在谈到“核心管理者”时，主要是技术负责人，而不是在公司内部进行传
统管理的人。如果你签署了采购订单或者对你的团队的预算有任何了解，你几乎肯定
不是一个核心管理者。这些建议可能适用于您，也可能不适用于您。

首先，我建议你购买“高效人的七个习惯”，而不是阅读它。烧了它，这是一个伟大的
象征性姿态。

.. [#cnf1] 本文件并不是通过回答问题，而是通过让提问者痛苦地明白，我们不知道
   答案是什么。

不管怎样，这里是：

.. _cn_decisions:

1）决策
-------

每个人都认为管理者做决定，而且决策很重要。决定越大越痛苦，管理者就必须越高级。
这很明显，但事实并非如此。

最重要的是 **避免** 做出决定。尤其是，如果有人告诉你“选择（a）或（b），
我们真的需要你来做决定”，你就是陷入麻烦的管理者。你管理的人比你更了解细节，
所以如果他们来找你做技术决策，你完蛋了。你显然没有能力为他们做这个决定。

（推论：如果你管理的人不比你更了解细节，你也会被搞砸，尽管原因完全不同。
也就是说，你的工作是错的，他们应该管理你的才智）

所以最重要的是 **避免** 做出决定，至少是那些大而痛苦的决定。做一些小的
和非结果性的决定是很好的，并且使您看起来好像知道自己在做什么，所以内核管理者
需要做的是将那些大的和痛苦的决定变成那些没有人真正关心的小事情。

这有助于认识到一个大的决定和一个小的决定之间的关键区别是你是否可以在事后修正
你的决定。任何决定都可以通过始终确保如果你错了（而且你一定会错），你以后总是
可以通过回溯来弥补损失。突然间，你就要做两个无关紧要的决定，一个是错误的，另
一个是正确的。

人们甚至会认为这是真正的领导能力（咳，胡说，咳）。

因此，避免重大决策的关键在于避免做那些无法挽回的事情。不要被引导到一个你无法
逃离的角落。走投无路的老鼠可能很危险——走投无路的管理者真可怜。

事实证明，由于没有人会愚蠢到让内核管理者承担巨大的财政责任，所以通常很容易
回溯。既然你不可能浪费掉你无法偿还的巨额资金，你唯一可以回溯的就是技术决策，
而回溯很容易：只要告诉大家你是个不称职的傻瓜，说对不起，然后撤销你去年让别
人所做的毫无价值的工作。突然间，你一年前做的决定不在是一个重大的决定，因为
它很容易被推翻。

事实证明，有些人对接受这种方法有困难，原因有两个：

 - 承认你是个白痴比看起来更难。我们都喜欢保持形象，在公共场合说你错了有时
   确实很难。
 - 如果有人告诉你，你去年所做的工作终究是不值得的，那么对那些可怜的低级工
   程师来说也是很困难的，虽然实际的 **工作** 很容易删除，但你可能已经不可
   挽回地失去了工程师的信任。记住：“不可撤销”是我们一开始就试图避免的，
   而你的决定终究是一个重大的决定。

令人欣慰的是，这两个原因都可以通过预先承认你没有任何线索，提前告诉人们你的
决定完全是初步的，而且可能是错误的事情来有效地缓解。你应该始终保留改变主意
的权利，并让人们 **意识** 到这一点。当你 **还没有** 做过真正愚蠢的事情的时
候，承认自己是愚蠢的要容易得多。

然后，当它真的被证明是愚蠢的时候，人们就转动他们的眼珠说“哎呀，下次不要了”。

这种对不称职的先发制人的承认，也可能使真正做这项工作的人也会三思是否值得做。
毕竟，如果他们不确定这是否是一个好主意，你肯定不应该通过向他们保证他们所做
的工作将会进入（内核）鼓励他们。在他们开始一项巨大的努力之前，至少让他们三
思而后行。

记住：他们最好比你更了解细节，而且他们通常认为他们对每件事都有答案。作为一
个管理者，你能做的最好的事情不是灌输自信，而是对他们所做的事情进行健康的批
判性思考。

顺便说一句，另一种避免做出决定的方法是看起来很可怜的抱怨 “我们不能两者兼
得吗？” 相信我，它是有效的。如果不清楚哪种方法更好，他们最终会弄清楚的。
最终的答案可能是两个团队都会因为这种情况而感到沮丧，以至于他们放弃了。

这听起来像是一个失败，但这通常是一个迹象，表明两个项目都有问题，而参与其中
的人不能做决定的原因是他们都是错误的。你最终会闻到玫瑰的味道，你避免了另一
个你本可以搞砸的决定。

2）人
-----

大多数人都是白痴，做一名管理者意味着你必须处理好这件事，也许更重要的是,
**他们** 必须处理好你。

事实证明，虽然很容易纠正技术错误，但不容易纠正人格障碍。你只能和他们的和
你的（人格障碍）共处。

但是，为了做好作为内核管理者的准备，最好记住不要烧掉任何桥梁，不要轰炸任何
无辜的村民，也不要疏远太多的内核开发人员。事实证明，疏远人是相当容易的，而
亲近一个疏远的人是很难的。因此，“疏远”立即属于“不可逆”的范畴，并根据
:ref:`cn_decisions` 成为绝不可以做的事情。

这里只有几个简单的规则：

 (1) 不要叫人笨蛋（至少不要在公共场合）
 (2) 学习如何在忘记规则(1)时道歉

问题在于 #1 很容易去做，因为你可以用数百万种不同的方式说“你是一个笨蛋” [#cnf2]_
有时甚至没有意识到，而且几乎总是带着一种白热化的信念，认为你是对的。

你越确信自己是对的（让我们面对现实吧，你可以把几乎所有人都称为坏人，而且你
经常是对的），事后道歉就越难。

要解决此问题，您实际上只有两个选项：

 - 非常擅长道歉
 - 把“爱”均匀地散开，没有人会真正感觉到自己被不公平地瞄准了。让它有足够的
   创造性，他们甚至可能会觉得好笑。

选择永远保持礼貌是不存在的。没有人会相信一个如此明显地隐藏了他们真实性格的人。

.. [#cnf2] 保罗·西蒙演唱了“离开爱人的50种方法”，因为坦率地说，“告诉开发者
   他们是D*CKHEAD" 的100万种方法都无法确认。但我确信他已经这么想了。

3）人2 - 好人
-------------

虽然大多数人都是白痴，但不幸的是，据此推论你也是白痴，尽管我们都自我感觉良
好，我们比普通人更好（让我们面对现实吧，没有人相信他们是普通人或低于普通人），
我们也应该承认我们不是最锋利的刀，而且会有其他人比你更不像白痴。

有些人对聪明人反应不好。其他人利用它们。

作为内核维护人员，确保您在第二组中。接受他们，因为他们会让你的工作更容易。
特别是，他们能够为你做决定，这就是游戏的全部内容。

所以当你发现一个比你聪明的人时，就顺其自然吧。你的管理职责在很大程度上变成
了“听起来像是个好主意——去尝试吧”，或者“听起来不错，但是XXX呢？”“。第二个版
本尤其是一个很好的方法，要么学习一些关于“XXX”的新东西，要么通过指出一些聪明
人没有想到的东西来显得更具管理性。无论哪种情况，你都会赢。

要注意的一件事是认识到一个领域的伟大不一定会转化为其他领域。所以你可能会向
特定的方向刺激人们，但让我们面对现实吧，他们可能擅长他们所做的事情，而且对
其他事情都很差劲。好消息是，人们往往会自然而然地重拾他们擅长的东西，所以当
你向某个方向刺激他们时，你并不是在做不可逆转的事情，只是不要用力推。

4）责备
-------

事情会出问题的，人们希望去责备人。贴标签，你就是受责备的人。

事实上，接受责备并不难，尤其是当人们意识到这不 **全是** 你的过错时。这让我
们找到了承担责任的最佳方式：为别人承担这件事。你会感觉很好，他们会感觉很好，
没有受到指责. 那谁，失去了他们的全部36GB色情收藏的人，因为你的无能将勉强承
认，你至少没有试图逃避责任。

然后让真正搞砸了的开发人员（如果你能找到他们）私下知道他们搞砸了。不仅是为
了将来可以避免，而且为了让他们知道他们欠你一个人情。而且，也许更重要的是，
他们也可能是能够解决问题的人。因为，让我们面对现实吧，肯定不是你。

承担责任也是你首先成为管理者的原因。这是让人们信任你，让你获得潜在的荣耀的
一部分，因为你就是那个会说“我搞砸了”的人。如果你已经遵循了以前的规则，你现
在已经很擅长说了。

5）应避免的事情
---------------

有一件事人们甚至比被称为“笨蛋”更讨厌，那就是在一个神圣的声音中被称为“笨蛋”。
第一个你可以道歉，第二个你不会真正得到机会。即使你做得很好，他们也可能不再
倾听。

我们都认为自己比别人强，这意味着当别人装腔作势时，这会让我们很恼火。你也许
在道德和智力上比你周围的每个人都优越，但不要试图太明显，除非你真的打算激怒
某人 [#cnf3]_

同样，不要对事情太客气或太微妙。礼貌很容易落得落花流水，把问题隐藏起来，
正如他们所说，“在互联网上，没人能听到你的含蓄。”用一个钝器把这一点锤进去，
因为你不能真的依靠别人来获得你的观点。

一些幽默可以帮助缓和直率和道德化。过度到荒谬的地步，可以灌输一个观点，而不
会让接受者感到痛苦，他们只是认为你是愚蠢的。因此，它可以帮助我们摆脱对批评
的个人心理障碍。

.. [#cnf3] 提示：与你的工作没有直接关系的网络新闻组是消除你对他人不满的好
   方法。偶尔写些侮辱性的帖子，打个喷嚏，让你的情绪得到净化。别把牢骚带回家

6）为什么是我？
---------------

既然你的主要责任似乎是为别人的错误承担责任，并且让别人痛苦地明白你是不称职
的，那么显而易见的问题之一就变成了为什么首先要这样做。

首先，虽然你可能会或可能不会听到十几岁女孩（或男孩，让我们不要在这里评判或
性别歧视）敲你的更衣室门，你会得到一个巨大的个人成就感为“负责”。别介意你真
的在领导别人，你要跟上别人，尽可能快地追赶他们。每个人都会认为你是负责人。

如果你可以做到这个， 这是个伟大的工作！


code:
.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>

.. _cn_programming_language:

程序设计语言
============

内核是用C语言 :ref:`c-language <cn_c-language>` 编写的。更准确地说，内核通常是用 :ref:`gcc <cn_gcc>`
在 ``-std=gnu11`` :ref:`gcc-c-dialect-options <cn_gcc-c-dialect-options>` 下编译的：ISO C11的 GNU 方言

这种方言包含对语言 :ref:`gnu-extensions <cn_gnu-extensions>` 的许多扩展，当然，它们许多都在内核中使用。

对于一些体系结构，有一些使用 :ref:`clang <cn_clang>` 和 :ref:`icc <cn_icc>` 编译内核
的支持，尽管在编写此文档时还没有完成，仍需要第三方补丁。

属性
----

在整个内核中使用的一个常见扩展是属性（attributes） :ref:`gcc-attribute-syntax <cn_gcc-attribute-syntax>`
属性允许将实现定义的语义引入语言实体（如变量、函数或类型），而无需对语言进行
重大的语法更改（例如添加新关键字） :ref:`n2049 <cn_n2049>`

在某些情况下，属性是可选的（即不支持这些属性的编译器仍然应该生成正确的代码，
即使其速度较慢或执行的编译时检查/诊断次数不够）

内核定义了伪关键字（例如， ``pure`` ），而不是直接使用GNU属性语法（例如,
``__attribute__((__pure__))`` ），以检测可以使用哪些关键字和/或缩短代码, 具体
请参阅 ``include/linux/compiler_attributes.h``

.. _cn_c-language:

c-language
   http://www.open-std.org/jtc1/sc22/wg14/www/standards

.. _cn_gcc:

gcc
   https://gcc.gnu.org

.. _cn_clang:

clang
   https://clang.llvm.org

.. _cn_icc:

icc
   https://software.intel.com/en-us/c-compilers

.. _cn_gcc-c-dialect-options:

c-dialect-options
   https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html

.. _cn_gnu-extensions:

gnu-extensions
   https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html

.. _cn_gcc-attribute-syntax:

gcc-attribute-syntax
   https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html

.. _cn_n2049:

n2049
   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf


code:
.. _cn_stable_api_nonsense:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/stable-api-nonsense.rst
           <stable_api_nonsense>`

译者::

        中文版维护者： 钟宇  TripleX Chung <xxx.phy@gmail.com>
        中文版翻译者： 钟宇  TripleX Chung <xxx.phy@gmail.com>
        中文版校译者： 李阳  Li Yang <leoyang.li@nxp.com>

Linux 内核驱动接口
==================

写作本文档的目的，是为了解释为什么Linux既没有二进制内核接口，也没有稳定
的内核接口。这里所说的内核接口，是指内核里的接口，而不是内核和用户空间
的接口。内核到用户空间的接口，是提供给应用程序使用的系统调用，系统调用
在历史上几乎没有过变化，将来也不会有变化。我有一些老应用程序是在0.9版本
或者更早版本的内核上编译的，在使用2.6版本内核的Linux发布上依然用得很好
。用户和应用程序作者可以将这个接口看成是稳定的。

执行纲要
--------

你也许以为自己想要稳定的内核接口，但是你不清楚你要的实际上不是它。你需
要的其实是稳定的驱动程序，而你只有将驱动程序放到公版内核的源代码树里，
才有可能达到这个目的。而且这样做还有很多其它好处，正是因为这些好处使得
Linux能成为强壮，稳定，成熟的操作系统，这也是你最开始选择Linux的原因。

入门
-----

只有那些写驱动程序的“怪人”才会担心内核接口的改变，对广大用户来说，既
看不到内核接口，也不需要去关心它。

首先，我不打算讨论关于任何非GPL许可的内核驱动的法律问题，这些非GPL许可
的驱动程序包括不公开源代码，隐藏源代码，二进制或者是用源代码包装，或者
是其它任何形式的不能以GPL许可公开源代码的驱动程序。如果有法律问题，请咨
询律师，我只是一个程序员，所以我只打算探讨技术问题（不是小看法律问题，
法律问题很实际，并且需要一直关注）。

既然只谈技术问题，我们就有了下面两个主题：二进制内核接口和稳定的内核源
代码接口。这两个问题是互相关联的，让我们先解决掉二进制接口的问题。

二进制内核接口
--------------
假如我们有一个稳定的内核源代码接口，那么自然而然的，我们就拥有了稳定的
二进制接口，是这样的吗？错。让我们看看关于Linux内核的几点事实：

    - 取决于所用的C编译器的版本，不同的内核数据结构里的结构体的对齐方
      式会有差别，代码中不同函数的表现形式也不一样（函数是不是被inline
      编译取决于编译器行为）。不同的函数的表现形式并不重要，但是数据
      结构内部的对齐方式很关键。

    - 取决于内核的配置选项，不同的选项会让内核的很多东西发生改变：

      - 同一个结构体可能包含不同的成员变量
      - 有的函数可能根本不会被实现（比如编译的时候没有选择SMP支持
        一些锁函数就会被定义成空函数）。
      - 内核使用的内存会以不同的方式对齐，这取决于不同的内核配置选
        项。

    - Linux可以在很多的不同体系结构的处理器上运行。在某个体系结构上编
      译好的二进制驱动程序，不可能在另外一个体系结构上正确的运行。

对于一个特定的内核，满足这些条件并不难，使用同一个C编译器和同样的内核配
置选项来编译驱动程序模块就可以了。这对于给一个特定Linux发布的特定版本提
供驱动程序，是完全可以满足需求的。但是如果你要给不同发布的不同版本都发
布一个驱动程序，就需要在每个发布上用不同的内核设置参数都编译一次内核，
这简直跟噩梦一样。而且还要注意到，每个Linux发布还提供不同的Linux内核，
这些内核都针对不同的硬件类型进行了优化（有很多种不同的处理器，还有不同
的内核设置选项）。所以每发布一次驱动程序，都需要提供很多不同版本的内核
模块。

相信我，如果你真的要采取这种发布方式，一定会慢慢疯掉，我很久以前就有过
深刻的教训...

稳定的内核源代码接口
--------------------

如果有人不将他的内核驱动程序，放入公版内核的源代码树，而又想让驱动程序
一直保持在最新的内核中可用，那么这个话题将会变得没完没了。
内核开发是持续而且快节奏的，从来都不会慢下来。内核开发人员在当前接口中
找到bug，或者找到更好的实现方式。一旦发现这些，他们就很快会去修改当前的
接口。修改接口意味着，函数名可能会改变，结构体可能被扩充或者删减，函数
的参数也可能发生改变。一旦接口被修改，内核中使用这些接口的地方需要同时
修正，这样才能保证所有的东西继续工作。

举一个例子，内核的USB驱动程序接口在USB子系统的整个生命周期中，至少经历
了三次重写。这些重写解决以下问题：

    - 把数据流从同步模式改成非同步模式，这个改动减少了一些驱动程序的
      复杂度，提高了所有USB驱动程序的吞吐率，这样几乎所有的USB设备都
      能以最大速率工作了。
    - 修改了USB核心代码中为USB驱动分配数据包内存的方式，所有的驱动都
      需要提供更多的参数给USB核心，以修正了很多已经被记录在案的死锁。

这和一些封闭源代码的操作系统形成鲜明的对比，在那些操作系统上，不得不额
外的维护旧的USB接口。这导致了一个可能性，新的开发者依然会不小心使用旧的
接口，以不恰当的方式编写代码，进而影响到操作系统的稳定性。
在上面的例子中，所有的开发者都同意这些重要的改动，在这样的情况下修改代
价很低。如果Linux保持一个稳定的内核源代码接口，那么就得创建一个新的接口
；旧的，有问题的接口必须一直维护，给Linux USB开发者带来额外的工作。既然
所有的Linux USB驱动的作者都是利用自己的时间工作，那么要求他们去做毫无意
义的免费额外工作，是不可能的。
安全问题对Linux来说十分重要。一个安全问题被发现，就会在短时间内得到修
正。在很多情况下，这将导致Linux内核中的一些接口被重写，以从根本上避免安
全问题。一旦接口被重写，所有使用这些接口的驱动程序，必须同时得到修正，
以确定安全问题已经得到修复并且不可能在未来还有同样的安全问题。如果内核
内部接口不允许改变，那么就不可能修复这样的安全问题，也不可能确认这样的
安全问题以后不会发生。
开发者一直在清理内核接口。如果一个接口没有人在使用了，它就会被删除。这
样可以确保内核尽可能的小，而且所有潜在的接口都会得到尽可能完整的测试
（没有人使用的接口是不可能得到良好的测试的）。

要做什么
--------

如果你写了一个Linux内核驱动，但是它还不在Linux源代码树里，作为一个开发
者，你应该怎么做？为每个发布的每个版本提供一个二进制驱动，那简直是一个
噩梦，要跟上永远处于变化之中的内核接口，也是一件辛苦活。
很简单，让你的驱动进入内核源代码树（要记得我们在谈论的是以GPL许可发行
的驱动，如果你的代码不符合GPL，那么祝你好运，你只能自己解决这个问题了，
你这个吸血鬼<把Andrew和Linus对吸血鬼的定义链接到这里>）。当你的代码加入
公版内核源代码树之后，如果一个内核接口改变，你的驱动会直接被修改接口的
那个人修改。保证你的驱动永远都可以编译通过，并且一直工作，你几乎不需要
做什么事情。

把驱动放到内核源代码树里会有很多的好处：

    - 驱动的质量会提升，而维护成本（对原始作者来说）会下降。
    - 其他人会给驱动添加新特性。
    - 其他人会找到驱动中的bug并修复。
    - 其他人会在驱动中找到性能优化的机会。
    - 当外部的接口的改变需要修改驱动程序的时候，其他人会修改驱动程序
    - 不需要联系任何发行商，这个驱动会自动的随着所有的Linux发布一起发
      布。

和别的操作系统相比，Linux为更多不同的设备提供现成的驱动，而且能在更多不
同体系结构的处理器上支持这些设备。这个经过考验的开发模式，必然是错不了
的 :)

感谢
----
感谢 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。

英文版维护者： Greg Kroah-Hartman <greg@kroah.com>


code:
.. _cn_stable_kernel_rules:

.. include:: ../disclaimer-zh_CN.rst

:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`

如果想评论或更新本文的内容，请直接联系原文档的维护者。如果你使用英文
交流有困难的话，也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题，请联系中文版维护者::

        中文版维护者： 钟宇  TripleX Chung <xxx.phy@gmail.com>
        中文版翻译者： 钟宇  TripleX Chung <xxx.phy@gmail.com>
        中文版校译者：
            - 李阳  Li Yang <leoyang.li@nxp.com>
            - Kangkai Yin <e12051@motorola.com>

所有你想知道的事情 - 关于linux稳定版发布
========================================

关于Linux 2.6稳定版发布，所有你想知道的事情。

关于哪些类型的补丁可以被接收进入稳定版代码树，哪些不可以的规则：
----------------------------------------------------------------

  - 必须是显而易见的正确，并且经过测试的。
  - 连同上下文，不能大于100行。
  - 必须只修正一件事情。
  - 必须修正了一个给大家带来麻烦的真正的bug（不是“这也许是一个问题...”
    那样的东西）。
  - 必须修正带来如下后果的问题：编译错误（对被标记为CONFIG_BROKEN的例外），
    内核崩溃，挂起，数据损坏，真正的安全问题，或者一些类似“哦，这不
    好”的问题。简短的说，就是一些致命的问题。
  - 没有“理论上的竞争条件”，除非能给出竞争条件如何被利用的解释。
  - 不能存在任何的“琐碎的”修正（拼写修正，去掉多余空格之类的）。
  - 必须被相关子系统的维护者接受。
  - 必须遵循Documentation/translations/zh_CN/process/submitting-patches.rst里的规则。

向稳定版代码树提交补丁的过程：
------------------------------

  - 在确认了补丁符合以上的规则后，将补丁发送到stable@vger.kernel.org。
  - 如果补丁被接受到队列里，发送者会收到一个ACK回复，如果没有被接受，收
    到的是NAK回复。回复需要几天的时间，这取决于开发者的时间安排。
  - 被接受的补丁会被加到稳定版本队列里，等待其他开发者的审查。
  - 安全方面的补丁不要发到这个列表，应该发送到security@kernel.org。

审查周期：
----------

  - 当稳定版的维护者决定开始一个审查周期，补丁将被发送到审查委员会，以
    及被补丁影响的领域的维护者（除非提交者就是该领域的维护者）并且抄送
    到linux-kernel邮件列表。
  - 审查委员会有48小时的时间，用来决定给该补丁回复ACK还是NAK。
  - 如果委员会中有成员拒绝这个补丁，或者linux-kernel列表上有人反对这个
    补丁，并提出维护者和审查委员会之前没有意识到的问题，补丁会从队列中
    丢弃。
  - 在审查周期结束的时候，那些得到ACK回应的补丁将会被加入到最新的稳定版
    发布中，一个新的稳定版发布就此产生。
  - 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中，而不是通过
    通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。

审查委员会：
------------
  - 由一些自愿承担这项任务的内核开发者，和几个非志愿的组成。


code:
.. include:: ../disclaimer-zh_CN.rst

:Original: Documentation/process/submit-checklist.rst
:Translator:
 - Alex Shi <alexs@kernel.org>
 - Wu XiangCheng <bobwxc@email.cn>

.. _cn_submitchecklist:

Linux内核补丁提交检查单
~~~~~~~~~~~~~~~~~~~~~~~

如果开发人员希望看到他们的内核补丁提交更快地被接受，那么他们应该做一些基本
的事情。

这些都是在 Documentation/translations/zh_CN/process/submitting-patches.rst
和其他有关提交Linux内核补丁的文档中提供的。

1) 如果使用工具，则包括定义/声明该工具的文件。不要依赖其他头文件来引入您使用
   的头文件。

2) 干净的编译：

   a) 使用合适的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有 ``gcc``
      警告/错误，没有链接器警告/错误。

   b) 通过 ``allnoconfig`` 、 ``allmodconfig``

   c) 使用 ``O=builddir`` 时可以成功编译

   d) 任何 Doucmentation/ 下的变更都能成功构建且不引入新警告/错误。
      用 ``make htmldocs`` 或 ``make pdfdocs`` 检验构建情况并修复问题。

3) 通过使用本地交叉编译工具或其他一些构建设施在多个CPU体系结构上构建。

4) PPC64是一种很好的交叉编译检查体系结构，因为它倾向于对64位的数使用无符号
   长整型。

5) 按 Documentation/translations/zh_CN/process/coding-style.rst 所述检查您的
   补丁是否为常规样式。在提交之前使用补丁样式检查器 ``scripts/checkpatch.pl``
   检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
   违规行为。

6) 任何新的或修改过的 ``CONFIG`` 选项都不应搞乱配置菜单，并默认为关闭，除非
   它们符合 ``Documentation/kbuild/kconfig-language.rst`` 菜单属性：默认值中
   记录的例外条件。

7) 所有新的 ``kconfig`` 选项都有帮助文本。

8) 已仔细审查了相关的 ``Kconfig`` 组合。这很难用测试来纠正——脑力在这里是有
   回报的。

9) 通过 sparse 清查。
   （参见 Documentation/translations/zh_CN/dev-tools/sparse.rst ）

10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何
    问题。

    .. note::

        ``checkstack`` 并不会明确指出问题，但是任何一个在堆栈上使用超过512
        字节的函数都可以进行更改。

11) 包括 :ref:`kernel-doc <kernel_doc_zh>` 内核文档以记录全局内核API。（静态
    函数不需要，但也可以。）使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
    :ref:`kernel-doc <kernel_doc_zh>` 并修复任何问题。

12) 通过以下选项同时启用的测试： ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
    ``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
    ``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
    ``CONFIG_PROVE_RCU`` 和 ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` 。

13) 在 ``CONFIG_SMP``, ``CONFIG_PREEMPT`` 开启和关闭的情况下都进行构建和运行
    时测试。

14) 所有代码路径都已在启用所有死锁检测（lockdep）功能的情况下运行。

15) 所有新的 ``/proc`` 条目都记录在 ``Documentation/``

16) 所有新的内核引导参数都记录在
    Documentation/admin-guide/kernel-parameters.rst 中。

17) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``

18) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息，
    请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送
    linux-api@vger.kernel.org。

19) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/`` 。
    如果新代码是实质性的，那么添加子系统特定的故障注入可能是合适的。

20) 新添加的代码已经用 ``gcc -W`` 编译（使用 ``make EXTRA-CFLAGS=-W`` ）。这
    将产生大量噪声，但对于查找诸如“警告：有符号和无符号之间的比较”之类的错误
    很有用。

21) 在它被合并到-mm补丁集中之后进行测试，以确保它仍然与所有其他排队的补丁以
    及VM、VFS和其他子系统中的各种更改一起工作。

22) 所有内存屏障（例如 ``barrier()``, ``rmb()``, ``wmb()`` ）都需要源代码注
    释来解释它们正在执行的操作及其原因的逻辑。

23) 如果补丁添加了任何ioctl，那么也要更新
    ``Documentation/userspace-api/ioctl/ioctl-number.rst`` 。

24) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
    功能，则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` （如果该选项可用）的情况
    下测试以下多个构建[并非所有这些都同时存在，只是它们的各种/随机组合]：

    ``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``,
    ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
    ``CONFIG_NET``, ``CONFIG_INET=n`` （但是最后一个需要 ``CONFIG_NET=y`` ）。


code:
.. SPDX-License-Identifier: GPL-2.0-or-later

.. include:: ../disclaimer-zh_CN.rst

.. _cn_submittingpatches:

:Original: Documentation/process/submitting-patches.rst

:译者:
 - 钟宇 TripleX Chung <xxx.phy@gmail.com>
 - 时奎亮 Alex Shi <alexs@kernel.org>
 - 吴想成 Wu XiangCheng <bobwxc@email.cn>

:校译:
 - 李阳 Li Yang <leoyang.li@nxp.com>
 - 王聪 Wang Cong <xiyou.wangcong@gmail.com>

提交补丁：如何让你的改动进入内核
================================

对于想要将改动提交到 Linux 内核的个人或者公司来说，如果不熟悉“规矩”，
提交的流程会让人畏惧。本文档包含了一系列建议，可以大大提高你
的改动被接受的机会.

本文档以较为简洁的行文给出了大量建议。关于内核开发流程如何进行的详细信息，
参见： Documentation/translations/zh_CN/process/development-process.rst 。
Documentation/translations/zh_CN/process/submit-checklist.rst 给出了一系列
提交补丁之前要检查的事项。设备树相关的补丁，请参阅
Documentation/devicetree/bindings/submitting-patches.rst 。

本文档假设您正在使用 ``git`` 准备你的补丁。如果您不熟悉 ``git`` ，最好学习
如何使用它，这将使您作为内核开发人员的生活变得更加轻松。

部分子系统和维护人员的树有一些关于其工作流程和要求的额外信息，请参阅
Documentation/process/maintainer-handbooks.rst 。

获取当前源码树
--------------

如果您手头没有当前内核源代码的存储库，请使用 ``git`` 获取一份。您需要先获取
主线存储库，它可以通过以下命令拉取::

    git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

但是，请注意，您可能不想直接针对主线树进行开发。大多数子系统维护人员运
行自己的树，并希望看到针对这些树准备的补丁。请参见MAINTAINERS文件中子系
统的 **T:** 项以查找该树，或者直接询问维护者该树是否未在其中列出。

.. _zh_describe_changes:

描述你的改动
------------

描述你的问题。无论您的补丁是一行错误修复还是5000行新功能，都必须有一个潜在
的问题激励您完成这项工作。说服审阅者相信有一个问题值得解决，让他们读完第一段
后就能明白这一点。

描述用户可见的影响。直接崩溃和锁定是相当有说服力的，但并不是所有的错误都那么
明目张胆。即使在代码审阅期间发现了这个问题，也要描述一下您认为它可能对用户产
生的影响。请记住，大多数Linux安装运行的内核来自二级稳定树或特定于供应商/产品
的树，只从上游精选特定的补丁，因此请包含任何可以帮助您将更改定位到下游的内容：
触发的场景、DMESG的摘录、崩溃描述、性能回归、延迟尖峰、锁定等。

质量优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
改进，请包括支持它们的数据。但也要描述不明显的成本。优化通常不是零成本的，而是
在CPU、内存和可读性之间进行权衡；或者，做探索性的工作，在不同的工作负载之间进
行权衡。请描述优化的预期缺点，以便审阅者可以权衡成本和收益。

提出问题之后，就要详细地描述一下您实际在做的技术细节。对于审阅者来说，用简练的
英语描述代码的变化是很重要的，以验证代码的行为是否符合您的意图。

如果您将补丁描述写成“标准格式”，可以很容易地作为“提交日志”放入Linux的源代
码管理系统 ``git`` 中，那么维护人员将非常感谢您。
参见 :ref:`zh_the_canonical_patch_format` 。

每个补丁只解决一个问题。如果你的描述开始变长，这就表明你可能需要拆分你的补丁。
请见 :ref:`zh_split_changes` 。

提交或重新提交补丁或补丁系列时，请包括完整的补丁说明和理由。不要
只说这是补丁（系列）的第几版。不要期望子系统维护人员引用更早的补丁版本或引用
URL来查找补丁描述并将其放入补丁中。也就是说，补丁（系列）及其描述应该是独立的。
这对维护人员和审阅者都有好处。一些审阅者可能甚至没有收到补丁的早期版本。

用祈使句描述你的变更，例如“make xyzzy do frotz”而不是“[This patch]make
xyzzy do frotz”或“[I]changed xyzzy to do frotz”，就好像你在命令代码库改变
它的行为一样。

如果您想要引用一个特定的提交，不要只引用提交的SHA-1 ID。还请包括提交的一行
摘要，以便于审阅者了解它是关于什么的。例如::

        Commit e21d2170f36602ae2708 ("video: remove unnecessary
        platform_set_drvdata()") removed the unnecessary
        platform_set_drvdata(), but left the variable "dev" unused,
        delete it.

您还应该确保至少使用前12位SHA-1 ID。内核存储库包含 *许多* 对象，使较短的ID
发生冲突的可能性很大。记住，即使现在不会与您的六个字符ID发生冲突，这种情况
也可能在五年后改变。

如果该变更的相关讨论或背景信息可以在网上查阅，请加上“Link:”标签指向它。例如
你的补丁修复了一个缺陷，需要添加一个带有URL的标签指向邮件列表存档或缺陷跟踪器
的相关报告；如果该补丁是由一些早先邮件列表讨论或网络上的记录引起的，请指向它。

当链接到邮件列表存档时，请首选lore.kernel.org邮件存档服务。用邮件中的
``Message-ID`` 头（去掉尖括号）可以创建链接URL。例如::

    Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/

请检查该链接以确保可用且指向正确的邮件。

不过，在没有外部资源的情况下，也要尽量让你的解释可理解。除了提供邮件列表存档或
缺陷的URL之外，还要需要总结该补丁的相关讨论要点。

如果补丁修复了特定提交中的错误，例如使用 ``git bisct`` 发现了一个问题，请使用
带有前12个字符SHA-1 ID的“Fixes:”标签和单行摘要。为了简化解析脚本，不要将该
标签拆分为多行，标签不受“75列换行”规则的限制。例如::

  Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")

下列 ``git config`` 设置可以让 ``git log``, ``git show`` 增加上述风格的显示格式::

	[core]
		abbrev = 12
	[pretty]
		fixes = Fixes: %h (\"%s\")

使用示例::

	$ git log -1 --pretty=fixes 54a4f0239f2e
	Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")

.. _zh_split_changes:

拆分你的改动
------------

将每个 **逻辑更改** 拆分成一个单独的补丁。

例如，如果你的改动里同时有bug修正和性能优化，那么把这些改动拆分到两个或
者更多的补丁文件中。如果你的改动包含对API的修改，并且增加了一个使用该新API
的驱动，那么把这些修改分成两个补丁。

另一方面，如果你将一个单独的改动做成多个补丁文件，那么将它们合并成一个
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。

需要记住的一点是，每个补丁的更改都应易于理解，以便审阅者验证。每个补丁都应该
对其价值进行阐述。

如果有一个补丁依赖另外一个补丁来完成它的改动，那没问题。直接在你的补
丁描述里指出 **“这个补丁依赖某补丁”** 就好了。

在将您的更改划分为一系列补丁时，要特别注意确保内核在应用系列中的每个补丁之后
都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何地方分
割你的补丁系列；如果你在中间引入错误，他们不会感谢你。

如果你不能将补丁系列浓缩得更小，那么每次大约发送出15个补丁，然后等待审阅
和集成。

检查你的更改风格
----------------

检查您的补丁是否违反了基本样式规定，详细信息参见
Documentation/translations/zh_CN/process/coding-style.rst
中找到。如果不这样做，只会浪费审阅者的时间，并且会导致你的补丁被拒绝，甚至
可能没有被阅读。

一个重要的例外是在将代码从一个文件移动到另一个文件时——在这种情况下，您不应
该在移动代码的同一个补丁中修改移动的代码。这清楚地描述了移动代码和您的更改
的行为。这大大有助于审阅实际差异，并允许工具更好地跟踪代码本身的历史。

在提交之前，使用补丁样式检查程序检查补丁（scripts/check patch.pl）。不过，
请注意，样式检查程序应该被视为一个指南，而不是作为人类判断的替代品。如果您
的代码看起来更好，但有违规行为，那么最好别管它。

检查者报告三个级别：

 - ERROR：很可能出错的事情
 - WARNING：需要仔细审阅的事项
 - CHECK：需要思考的事情

您应该能够判断您的补丁中存在的所有违规行为。

选择补丁收件人
--------------

您应该总是知会任何补丁相应代码的子系统维护人员；查看
维护人员文件和源代码修订历史记录，以了解这些维护人员是谁。脚本
scripts/get_maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
的维护人员，那么Andrew Morton（akpm@linux-foundation.org）将充当最后的维护
人员。

您通常还应该选择至少一个邮件列表来接收补丁集的副本。linux-kernel@vger.kernel.org
是所有补丁的默认列表，但是这个列表的流量已经导致了许多开发人员不再看它。
在MAINTAINERS文件中查找子系统特定的列表；您的补丁可能会在那里得到更多的关注。
不过，请不要发送垃圾邮件到无关的列表。

许多与内核相关的列表托管在vger.kernel.org上；您可以在
http://vger.kernel.org/vger-lists.html 上找到它们的列表。不过，也有与内核相关
的列表托管在其他地方。

不要一次发送超过15个补丁到vger邮件列表！！！！

Linus Torvalds是决定改动能否进入 Linux 内核的最终裁决者。他的邮件地址是
torvalds@linux-foundation.org 。他收到的邮件很多，所以一般来说最好 **别**
给他发邮件。

如果您有修复可利用安全漏洞的补丁，请将该补丁发送到 security@kernel.org 。对于
严重的bug，可以考虑短期禁令以允许分销商（有时间）向用户发布补丁；在这种情况下，
显然不应将补丁发送到任何公共列表。
参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。

修复已发布内核中严重错误的补丁程序应该抄送给稳定版维护人员，方法是把以下列行
放进补丁的签准区（注意，不是电子邮件收件人）::

  Cc: stable@vger.kernel.org

除了本文件之外，您还应该阅读
Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。

如果更改影响到用户侧内核接口，请向手册页维护人员（如维护人员文件中所列）发送
手册页补丁，或至少发送更改通知，以便一些信息进入手册页。还应将用户空间API
更改抄送到 linux-api@vger.kernel.org 。

不要MIME编码，不要链接，不要压缩，不要附件，只要纯文本
------------------------------------------------------

Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
，可以“引用”你的改动很重要，使用一般的邮件工具，他们就可以在你的
代码的任何位置添加评论。

因为这个原因，所有的提交的补丁都是邮件中“内嵌”的。最简单（和推荐）的方法就
是使用 ``git send-email`` 。https://git-send-email.io 有 ``git send-email``
的交互式教程。

如果你选择不用 ``git send-email`` ：

.. warning::

  如果你使用剪切-粘贴你的补丁，小心你的编辑器的自动换行功能破坏你的补丁

不要将补丁作为MIME编码的附件，不管是否压缩。很多流行的邮件软件不
是任何时候都将MIME编码的附件当作纯文本发送的，这会使得别人无法在你的
代码中加评论。另外，MIME编码的附件会让Linus多花一点时间来处理，这就
降低了你的改动被接受的可能性。

例外：如果你的邮路损坏了补丁，那么有人可能会要求你使用MIME重新发送补丁。

请参阅 Documentation/translations/zh_CN/process/email-clients.rst
以获取有关配置电子邮件客户端以使其不受影响地发送补丁的提示。

回复审阅意见
------------

你的补丁几乎肯定会得到审阅者对补丁改进方法的评论（以回复邮件的形式）。您必须
对这些评论作出回应；让补丁被忽略的一个好办法就是忽略审阅者的意见。直接回复邮
件来回应意见即可。不会导致代码更改的意见或问题几乎肯定会带来注释或变更日志的
改变，以便下一个审阅者更好地了解正在发生的事情。

一定要告诉审阅者你在做什么改变，并感谢他们的时间。代码审阅是一个累人且耗时的
过程，审阅者有时会变得暴躁。即使在这种情况下，也要礼貌地回应并解决他们指出的
问题。当发送下一版时，在封面邮件或独立补丁里加上 ``patch changelog`` 说明与
前一版本的不同之处（参见 :ref:`zh_the_canonical_patch_format` ）。

.. _zh_resend_reminders:

不要泄气或不耐烦
----------------

提交更改后，请耐心等待。审阅者是大忙人，可能无法立即审阅您的补丁。

曾几何时，补丁曾在没收到评论的情况下消失在虚空中，但现在开发过程应该更加顺利了。
您应该在一周左右的时间内收到评论；如果没有收到评论，请确保您已将补丁发送
到正确的位置。在重新提交或联系审阅者之前至少等待一周——在诸如合并窗口之类的
繁忙时间可能更长。

在等了几个星期后，用带RESEND的主题重发补丁也是可以的::

   [PATCH Vx RESEND] sub/sys: Condensed patch summary

当你发布补丁（系列）修改版的时候，不要加上“RESEND”——“RESEND”只适用于重
新提交之前未经修改的补丁（系列）。

主题中包含 PATCH
----------------

由于到Linus和linux-kernel的电子邮件流量很高，通常会在主题行前面加上[PATCH]
前缀。这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。

``git send-email`` 会自动为你加上。

签署你的作品——开发者来源认证
------------------------------

为了加强对谁做了何事的追踪，尤其是对那些透过好几层维护者才最终到达的补丁，我
们在通过邮件发送的补丁上引入了“签署（sign-off）”流程。

“签署”是在补丁注释最后的一行简单文字，认证你编写了它或者其他
人有权力将它作为开放源代码的补丁传递。规则很简单：如果你能认证如下信息:

开发者来源认证 1.1
^^^^^^^^^^^^^^^^^^

对于本项目的贡献，我认证如下信息：

       (a) 这些贡献是完全或者部分的由我创建，我有权利以文件中指出
           的开放源代码许可证提交它；或者

       (b) 这些贡献基于以前的工作，据我所知，这些以前的工作受恰当的开放
           源代码许可证保护，而且，根据文件中指出的许可证，我有权提交修改后的贡献，
           无论是完全还是部分由我创造，这些贡献都使用同一个开放源代码许可证
           （除非我被允许用其它的许可证）；或者

       (c) 这些贡献由认证（a），（b）或者（c）的人直接提供给我，而
           且我没有修改它。

       (d) 我理解并同意这个项目和贡献是公开的，贡献的记录（包括我
           一起提交的个人记录，包括sign-off）被永久维护并且可以和这个项目
           或者开放源代码的许可证同步地再发行。

那么加入这样一行::

  Signed-off-by: Random J Developer <random@developer.example.org>

使用你的真名（抱歉，不能使用假名或者匿名。）如果使用 ``git commit -s`` 的话
将会自动完成。撤销也应当包含“Signed-off-by”， ``git revert -s`` 会帮你搞定。

有些人会在最后加上额外的标签。现在这些东西会被忽略，但是你可以这样做，来标记
公司内部的过程，或者只是指出关于签署的一些特殊细节。

作者签署之后的任何其他签署（Signed-off-by:'s）均来自处理和传递补丁的人员，但
未参与其开发。签署链应当反映补丁传播到维护者并最终传播到Linus所经过的 **真实**
路径，首个签署指明单个作者的主要作者身份。

何时使用Acked-by:，CC:，和Co-Developed by:
------------------------------------------

Singed-off-by: 标签表示签名者参与了补丁的开发，或者他/她在补丁的传递路径中。

如果一个人没有直接参与补丁的准备或处理，但希望表示并记录他们对补丁的批准/赞成，
那么他们可以要求在补丁的变更日志中添加一个Acked-by:。

Acked-by: 通常由受影响代码的维护者使用，当该维护者既没有贡献也没有转发补丁时。

Acked-by: 不像签署那样正式。这是一个记录，确认人至少审阅了补丁，并表示接受。
因此，补丁合并有时会手动将Acker的“Yep，looks good to me”转换为 Acked-By:（但
请注意，通常最好要求一个明确的Ack）。

Acked-by：不一定表示对整个补丁的确认。例如，如果一个补丁影响多个子系统，并且
有一个来自某个子系统维护者的Acked-By:，那么这通常表示只确认影响维护者代码的部
分。这里应该仔细判断。如有疑问，应参考邮件列表存档中的原始讨论。

如果某人本应有机会对补丁进行评论，但没有提供此类评论，您可以选择在补丁中添加
``Cc:`` 这是唯一可以在没有被该人明确同意的情况下添加的标签——但它应该表明
这个人是在补丁上抄送的。此标签记录了讨论中包含的潜在利益相关方。

Co-developed-by: 声明补丁是由多个开发人员共同创建的；当几个人在一个补丁上工
作时，它用于给出共同作者（除了From:所给出的作者之外）。因为Co-developed-by:
表示作者身份，所以每个Co-developed-by:必须紧跟在相关合作作者的签署之后。标准
签署程序要求Singed-off-by:标签的顺序应尽可能反映补丁的时间历史，无论作者是通
过From:还是Co-developed-by:表明。值得注意的是，最后一个Singed-off-by:必须是
提交补丁的开发人员。

注意，如果From:作者也是电子邮件标题的From:行中列出的人，则From:标签是可选的。

被From:作者提交的补丁示例::

	<changelog>

	Co-developed-by: First Co-Author <first@coauthor.example.org>
	Signed-off-by: First Co-Author <first@coauthor.example.org>
	Co-developed-by: Second Co-Author <second@coauthor.example.org>
	Signed-off-by: Second Co-Author <second@coauthor.example.org>
	Signed-off-by: From Author <from@author.example.org>

被合作开发者提交的补丁示例::

	From: From Author <from@author.example.org>

	<changelog>

	Co-developed-by: Random Co-Author <random@coauthor.example.org>
	Signed-off-by: Random Co-Author <random@coauthor.example.org>
	Signed-off-by: From Author <from@author.example.org>
	Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
	Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>

使用Reported-by:、Tested-by:、Reviewed-by:、Suggested-by:和Fixes:
-----------------------------------------------------------------

Reported-by: 给那些发现错误并报告错误的人致谢，它希望激励他们在将来再次帮助
我们。请注意，如果bug是以私有方式报告的，那么在使用Reported-by标签之前，请
先请求许可。此标签是为Bug设计的；请不要将其用于感谢功能请求。

Tested-by: 标签表示补丁已由指定的人（在某些环境中）成功测试。这个标签通知
维护人员已经执行了一些测试，为将来的补丁提供了一种定位测试人员的方法，并彰显测试人员的功劳。

Reviewed-by：根据审阅者的监督声明，表明该补丁已被审阅并被认为是可接受的：

审阅者的监督声明
^^^^^^^^^^^^^^^^

通过提供我的Reviewed-by:标签，我声明：

        (a) 我已经对这个补丁进行了一次技术审阅，以评估它是否适合被包含到
            主线内核中。

        (b) 与补丁相关的任何问题、顾虑或问题都已反馈给提交者。我对提交者对
            我的评论的回应感到满意。

        (c) 虽然这一提交可能仍可被改进，但我相信，此时，（1）对内核
            进行了有价值的修改，（2）没有包含争论中涉及的已知问题。

        (d) 虽然我已经审阅了补丁并认为它是健全的，但我不会（除非另有明确
            说明）作出任何保证或担保它会在任何给定情况下实现其规定的目的
            或正常运行。

Reviewed-by是一种观点声明，即补丁是对内核的适当修改，没有任何遗留的严重技术
问题。任何感兴趣的审阅者（完成工作的人）都可以为一个补丁提供一个Reviewed-by
标签。此标签用于向审阅者提供致谢，并通知维护者补丁的审阅进度。
当Reviewed-by:标签由已知了解主题区域并执行彻底检查的审阅者提供时，通常会增加
补丁进入内核的可能性。

一旦从测试人员或审阅者的“Tested-by”和“Reviewed-by”标签出现在邮件列表中，
作者应在发送下一个版本时将其添加到适用的补丁中。但是，如果补丁在以下版本中发
生了实质性更改，这些标签可能不再适用，因此应该删除。通常，在补丁更改日志中
（在 ``---`` 分隔符之后）应该提到删除某人的测试者或审阅者标签。

Suggested-by: 表示补丁的想法是由指定的人提出的，并确保将此想法归功于指定的
人。请注意，未经许可，不得添加此标签，特别是如果该想法未在公共论坛上发布。
也就是说，如果我们勤快地致谢创意提供者，他们将受到鼓舞，很有希望在未来再次
帮助我们。

Fixes: 指示补丁修复了之前提交的一个问题。它可以便于确定错误的来源，这有助于
检查错误修复。这个标签还帮助稳定内核团队确定应该接收修复的稳定内核版本。这是
指示补丁修复的错误的首选方法。请参阅 :ref:`zh_describe_changes` 了解更多信息。

.. note::

  附加Fixes:标签不会改变稳定内核规则流程，也不改变所有稳定版补丁抄送
  stable@vger.kernel.org的要求。有关更多信息，请阅读
  Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。

.. _zh_the_canonical_patch_format:

标准补丁格式
------------

本节描述如何格式化补丁本身。请注意，如果您的补丁存储在 ``Git`` 存储库中，则
可以使用 ``git format-patch`` 进行正确的补丁格式化。但是，这些工具无法创建
必要的文本，因此请务必阅读下面的说明。

标准的补丁标题行是::

    Subject: [PATCH 001/123] 子系统:一句话概述

标准补丁的信体包含如下部分：

  - 一个 ``from`` 行指出补丁作者。后跟空行（仅当发送补丁的人不是作者时才需要）。

  - 说明文字，每行最长75列，这将被复制到永久变更日志来描述这个补丁。

  - 一个空行

  - 上述的 ``Signed-off-by:`` 行，也将出现在更改日志中。

  - 只包含 ``---`` 的标记线。

  - 任何其他不适合放在变更日志的注释。

  - 实际补丁（ ``diff`` 输出）。

标题行的格式，使得对标题行按字母序排序非常的容易——很多邮件客户端都
可以支持——因为序列号是用零填充的，所以按数字排序和按字母排序是一样的。

邮件标题中的“子系统”标识哪个内核子系统将被打补丁。

邮件标题中的“一句话概述”扼要的描述邮件中的补丁。“一句话概述”
不应该是一个文件名。对于一个补丁系列（“补丁系列”指一系列的多个相关补
丁），不要对每个补丁都使用同样的“一句话概述”。

记住邮件的“一句话概述”会成为该补丁的全局唯一标识。它会进入 ``git``
的改动记录里。然后“一句话概述”会被用在开发者的讨论里，用来指代这个补
丁。用户将希望通过搜索引擎搜索“一句话概述”来找到那些讨论这个补丁的文
章。当人们在两三个月后使用诸如 ``gitk`` 或 ``git log --oneline`` 之类
的工具查看数千个补丁时，也会很快看到它。

出于这些原因，概述必须不超过70-75个字符，并且必须描述补丁的更改以及为
什么需要补丁。既要简洁又要描述性很有挑战性，但写得好的概述应该这样。

概述的前缀可以用方括号括起来：“Subject: [PATCH <tag>...] <概述>”。标记
不被视为概述的一部分，而是描述应该如何处理补丁。如果补丁的多个版本已发
送出来以响应评审（即“v1，v2，v3”）则必须包含版本号，或包含“RFC”以指示
评审请求。如果一个补丁系列中有四个补丁，那么各个补丁可以这样编号：1/4、2/4、
3/4、4/4。这可以确保开发人员了解补丁应用的顺序，且
已经查看或应用了补丁系列中的所有补丁。

一些标题的例子::

    Subject: [patch 2/5] ext2: improve scalability of bitmap searching
    Subject: [PATCHv2 001/207] x86: fix eflags tracking

``From`` 行是信体里的最上面一行，具有如下格式::

        From: Patch Author <author@example.com>

``From`` 行指明在永久改动日志里，谁会被确认为作者。如果没有 ``From`` 行，那
么邮件头里的 ``From:`` 行会被用来决定改动日志中的作者。

说明文字将会被提交到永久的源代码改动日志里，因此应针对那些早已经不记得和这
个补丁相关的讨论细节的读者。包括补丁处理的故障症状（内核日志消息、oops消息
等），这对于可能正在搜索提交日志以查找适用补丁的人特别有用。文本应该写得如
此详细，以便在数周、数月甚至数年后阅读时，能够为读者提供所需的细节信息，以
掌握创建补丁的 **原因** 。

如果一个补丁修复了一个编译失败，那么可能不需要包含 *所有* 编译失败；
只要足够让搜索补丁的人能够找到它就行了。与概述一样，既要简洁又要描述性。

``---`` 标记行对于补丁处理工具要找到哪里是改动日志信息的结束，是不可缺少
的。

对于 ``---`` 标记之后的额外注解，一个好的用途就是用来写 ``diffstat`` ，用来显
示修改了什么文件和每个文件都增加和删除了多少行。 ``diffstat`` 对于比较大的补
丁特别有用。
使用 ``diffstat`` 的选项 ``-p 1 -w 70`` 这样文件名就会从内核源代码树的目录开始
，不会占用太宽的空间（很容易适合80列的宽度，也许会有一些缩进。）
（ ``git`` 默认会生成合适的diffstat。）

其余那些只适用于当时或者与维护者相关的注解，不合适放到永久的改动日志里的，也
应该放这里。较好的例子就是 ``补丁更改记录`` ，记录了v1和v2版本补丁之间的差异。

请将此信息放在将变更日志与补丁的其余部分分隔开的 ``---`` 行 **之后** 。版本
信息不是提交到git树的变更日志的一部分。只是供审阅人员使用的附加信息。如果将
其放置在提交标记上方，则需要手动交互才能将其删除。如果它位于分隔线以下，则在
应用补丁时会自动剥离::

  <commit message>
  ...
  Signed-off-by: Author <author@mail>
  ---
  V2 -> V3: Removed redundant helper function
  V1 -> V2: Cleaned up coding style and addressed review comments

  path/to/file | 5+++--
  ...

在后面的参考资料中能看到正确补丁格式的更多细节。

.. _zh_backtraces:

提交消息中的回溯（Backtraces）
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

回溯有助于记录导致问题的调用链。然而，并非所有回溯都有帮助。例如，早期引导调
用链是独特而明显的。而逐字复制完整的dmesg输出则会增加时间戳、模块列表、寄存
器和堆栈转储等分散注意力的信息。

因此，最有用的回溯应该从转储中提取相关信息，以更容易集中在真实问题上。下面是
一个剪裁良好的回溯示例::

  unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
  at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
  Call Trace:
  mba_wrmsr
  update_domains
  rdtgroup_mkdir

.. _zh_explicit_in_reply_to:

明确回复邮件头（In-Reply-To）
-----------------------------

手动添加回复补丁的的邮件头（In-Reply_To:）是有用的（例如，使用 ``git send-email`` ），
可以将补丁与以前的相关讨论关联起来，例如，将bug补丁链接到电子邮件和bug报告。
但是，对于多补丁系列，最好避免在回复时使用链接到该系列的旧版本。这样，
补丁的多个版本就不会成为电子邮件客户端中无法管理的引用树。如果链接有用，
可以使用 https://lore.kernel.org/ 重定向器（例如，在封面电子邮件文本中）
链接到补丁系列的早期版本。

给出基础树信息
--------------

当其他开发人员收到您的补丁并开始审阅时，知道应该将您的工作放到代码树历史记录
中的什么位置通常很有用。这对于自动化持续集成流水（CI）特别有用，这些流水线试
图运行一系列测试，以便在维护人员开始审阅之前确定提交的质量。

如果您使用 ``git format-patch`` 生成补丁，则可以通过 ``--base`` 标志在提交中
自动包含基础树信息。使用此选项最简单、最方便的方法是配合主题分支::

    $ git checkout -t -b my-topical-branch master
    Branch 'my-topical-branch' set up to track local branch 'master'.
    Switched to a new branch 'my-topical-branch'

    [perform your edits and commits]

    $ git format-patch --base=auto --cover-letter -o outgoing/ master
    outgoing/0000-cover-letter.patch
    outgoing/0001-First-Commit.patch
    outgoing/...

当你编辑 ``outgoing/0000-cover-letter.patch`` 时，您会注意到在它的最底部有一
行 ``base-commit:`` 尾注，它为审阅者和CI工具提供了足够的信息以正确执行
``git am`` 而不必担心冲突::

    $ git checkout -b patch-review [base-commit-id]
    Switched to a new branch 'patch-review'
    $ git am patches.mbox
    Applying: First Commit
    Applying: ...

有关此选项的更多信息，请参阅 ``man git-format-patch`` 。

.. note::

    ``--base`` 功能是在2.9.0版git中引入的。

如果您不使用git格式化补丁，仍然可以包含相同的 ``base-commit`` 尾注，以指示您
的工作所基于的树的提交哈希。你应该在封面邮件或系列的第一个补丁中添加它，它应
该放在 ``---`` 行的下面或所有其他内容之后，即只在你的电子邮件签名之前。

参考文献
--------

Andrew Morton，“完美的补丁”（tpp）
  <https://www.ozlabs.org/~akpm/stuff/tpp.txt>

Jeff Garzik，“Linux内核补丁提交格式”
  <https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>

Greg Kroah-Hartman，“如何惹恼内核子系统维护人员”
  <http://www.kroah.com/log/linux/maintainer.html>

  <http://www.kroah.com/log/linux/maintainer-02.html>

  <http://www.kroah.com/log/linux/maintainer-03.html>

  <http://www.kroah.com/log/linux/maintainer-04.html>

  <http://www.kroah.com/log/linux/maintainer-05.html>

  <http://www.kroah.com/log/linux/maintainer-06.html>

不！！！别再发巨型补丁炸弹给linux-kernel@vger.kernel.org的人们了！
  <https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>

内核 Documentation/translations/zh_CN/process/coding-style.rst

Linus Torvalds关于标准补丁格式的邮件
  <https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>

Andi Kleen，“提交补丁之路”
  一些帮助合入困难或有争议的变更的策略。

  http://halobates.de/on-submitting-patches.pdf