M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@@ -0,0 +1,701 @@
Chinese translated version of Documentation/CodingStyle
If you have any comment or update to the content, please post to LKML directly.
However, if you have problem communicating in English you can also ask the
Chinese maintainer for help. Contact the Chinese maintainer, if this
translation is outdated or there is problem with translation.
Chinese maintainer: Zhang Le <r0bertz@gentoo.org>
---------------------------------------------------------------------
Documentation/CodingStyle的中文翻译
如果想评论或更新本文的内容请直接发信到LKML。如果你使用英文交流有困难的话也可
以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org>
中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org>
中文版校译者: 王聪 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代码规范然后不要读它。烧了它这是一个具有重大象征性
意义的动作。
不管怎样,现在我们开始:
第一章:缩进
制表符是8个字符所以缩进也是8个字符。有些异端运动试图将缩进变为4乃至2个字符
这几乎相当于尝试将圆周率的值定义为3。
理由:缩进的全部意义就在于清楚的定义一个控制块起止于何处。尤其是当你盯着你的屏幕
连续看了20小时之后你将会发现大一点的缩进会使你更容易分辨缩进。
现在有些人会抱怨8个字符的缩进会使代码向右边移动的太远在80个字符的终端屏幕上
就很难读这样的代码。这个问题的答案是如果你需要3级以上的缩进不管用何种方式你
的代码已经有问题了,应该修正你的程序。
简而言之8个字符的缩进可以让代码更容易阅读还有一个好处是当你的函数嵌套太深的
时候可以给你警告。留心这个警告。
在switch语句中消除多级缩进的首选的方式是让“switch”和从属于它的“case”标签对齐于同
一列而不要“两次缩进”“case”标签。比如
switch (suffix) {
case 'G':
case 'g':
mem <<= 30;
break;
case 'M':
case 'm':
mem <<= 20;
break;
case 'K':
case 'k':
mem <<= 10;
/* fall through */
default:
break;
}
不要把多个语句放在一行里,除非你有什么东西要隐藏:
if (condition) do_this;
do_something_everytime;
也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读的表
达式。
除了注释、文档和Kconfig之外不要使用空格来缩进前面的例子是例外是有意为之。
选用一个好的编辑器,不要在行尾留空格。
第二章:把长的行和字符串打散
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
每一行的长度的限制是80列我们强烈建议您遵守这个惯例。
长于80列的语句要打散成有意义的片段。每个片段要明显短于原来的语句而且放置的位置
也明显的靠右。同样的规则也适用于有很长参数列表的函数头。长字符串也要打散成较短的
字符串。唯一的例外是超过80列可以大幅度提高可读性并且不会隐藏信息的情况。
void fun(int a, int b, int c)
{
if (condition)
printk(KERN_WARNING "Warning this is a long printk with "
"3 parameters a: %u b: %u "
"c: %u \n", a, b, c);
else
next_statement;
}
第三章:大括号和空格的放置
C语言风格中另外一个常见问题是大括号的放置。和缩进大小不同选择或弃用某种放置策
略并没有多少技术上的原因不过首选的方式就像Kernighan和Ritchie展示给我们的
把起始大括号放在行尾,而把结束大括号放在行首,所以:
if (x is true) {
we do y
}
这适用于所有的非函数语句块if、switch、for、while、do。比如
switch (action) {
case KOBJ_ADD:
return "add";
case KOBJ_REMOVE:
return "remove";
case KOBJ_CHANGE:
return "change";
default:
return NULL;
}
不过,有一个例外,那就是函数:函数的起始大括号放置于下一行的开头,所以:
int function(int x)
{
body of function
}
全世界的异端可能会抱怨这个不一致性是……呃……不一致的,不过所有思维健全的人都知道(
aK&R是_正确的_并且bK&R是正确的。此外不管怎样函数都是特殊的在C语言中
,函数是不能嵌套的)。
注意结束大括号独自占据一行除非它后面跟着同一个语句的剩余部分也就是do语句中的
“while”或者if语句中的“else”像这样
do {
body of do-loop
} while (condition);
if (x == y) {
..
} else if (x > y) {
...
} else {
....
}
理由K&R。
也请注意这种大括号的放置方式也能使空(或者差不多空的)行的数量最小化,同时不失可
读性。因此由于你的屏幕上的新行是不可再生资源想想25行的终端屏幕你将会有更
多的空行来放置注释。
当只有一个单独的语句的时候,不用加不必要的大括号。
if (condition)
action();
这点不适用于本身为某个条件语句的一个分支的单独语句。这时需要在两个分支里都使用大
括号。
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__这些关键字之后放空格。例如
s = sizeof(struct file);
不要在小括号里的表达式两侧加空格。这是一个反例:
s = sizeof( struct file );
当声明指针类型或者返回指针类型的函数时,“*”的首选使用方式是使之靠近变量名或者函
数名,而不是靠近类型名。例子:
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
在大多数二元和三元操作符两侧使用一个空格,例如下面所有这些操作符:
= + - < > * / % | & ^ <= >= == != ? :
但是一元操作符后不要加空格:
& * + - ~ ! sizeof typeof alignof __attribute__ defined
后缀自加和自减一元操作符前不加空格:
++ --
前缀自加和自减一元操作符后不加空格:
++ --
“.”和“->”结构体成员操作符前后不加空格。
不要在行尾留空白。有些可以自动缩进的编辑器会在新行的行首加入适量的空白,然后你
就可以直接在那一行输入代码。不过假如你最后没有在那一行输入代码,有些编辑器就不
会移除已经加入的空白,就像你故意留下一个只有空白的行。包含行尾空白的行就这样产
生了。
当git发现补丁包含了行尾空白的时候会警告你并且可以应你的要求去掉行尾空白不过
如果你是正在打一系列补丁,这样做会导致后面的补丁失败,因为你改变了补丁的上下文。
第四章:命名
C是一个简朴的语言你的命名也应该这样。和Modula-2和Pascal程序员不同C程序员不使
用类似ThisVariableIsATemporaryCounter这样华丽的名字。C程序员会称那个变量为“tmp”
,这样写起来会更容易,而且至少不会令其难于理解。
不过,虽然混用大小写的名字是不提倡使用的,但是全局变量还是需要一个具描述性的名字
。称一个全局函数为“foo”是一个难以饶恕的错误。
全局变量(只有当你真正需要它们的时候再用它)需要有一个具描述性的名字,就像全局函
数。如果你有一个可以计算活动用户数量的函数你应该叫它“count_active_users()”或者
类似的名字你不应该叫它“cntuser()”。
在函数名中包含函数类型(所谓的匈牙利命名法)是脑子出了问题——编译器知道那些类型而
且能够检查那些类型,这样做只能把程序员弄糊涂了。难怪微软总是制造出有问题的程序。
本地变量名应该简短,而且能够表达相关的含义。如果你有一些随机的整数型的循环计数器
它应该被称为“i”。叫它“loop_counter”并无益处如果它没有被误解的可能的话。类似
“tmp”可以用来称呼任意类型的临时变量。
如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综合症
。请看第六章(函数)。
第五章Typedef
不要使用类似“vps_t”之类的东西。
对结构体和指针使用typedef是一个错误。当你在代码里看到
vps_t a;
这代表什么意思呢?
相反,如果是这样
struct virtual_container *a;
你就知道“a”是什么了。
很多人认为typedef“能提高可读性”。实际不是这样的。它们只在下列情况下有用
(a) 完全不透明的对象这种情况下要主动使用typedef来隐藏这个对象实际上是什么
例如“pte_t”等不透明对象你只能用合适的访问函数来访问它们。
注意不透明性和“访问函数”本身是不好的。我们使用pte_t等类型的原因在于真的是
完全没有任何共用的可访问信息。
(b) 清楚的整数类型如此这层抽象就可以帮助消除到底是“int”还是“long”的混淆。
u8/u16/u32是完全没有问题的typedef不过它们更符合类别(d)而不是这里。
再次注意要这样做必须事出有因。如果某个变量是“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。
第六章:函数
函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完(我们都知
道ISO/ANSI屏幕大小是80x24只做一件事情而且把它做好。
一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。所以,如果你有一个理论上
很简单的只有一个很长但是简单的case语句的函数而且你需要在每个case里做很多很
小的事情,这样的函数尽管很长,但也是可以的。
不过,如果你有一个复杂的函数,而且你怀疑一个天分不是很高的高中一年级学生可能甚至
搞不清楚这个函数的目的,你应该严格的遵守前面提到的长度限制。使用辅助函数,并为之
取个具描述性的名字(如果你觉得它们的性能很重要的话,可以让编译器内联它们,这样的
效果往往会比你写一个复杂函数的效果要好。)
函数的另外一个衡量标准是本地变量的数量。此数量不应超过510个否则你的函数就有
问题了。重新考虑一下你的函数,把它分拆成更小的函数。人的大脑一般可以轻松的同时跟
踪7个不同的事物如果再增多的话就会糊涂了。即便你聪颖过人你也可能会记不清你2
个星期前做过的事情。
在源文件里使用空行隔开不同的函数。如果该函数需要被导出它的EXPORT*宏应该紧贴
在它的结束大括号之下。比如:
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
在函数原型中包含函数名和它们的数据类型。虽然C语言里没有这样的要求在Linux里这
是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
第七章:集中的函数退出途径
虽然被某些人声称已经过时但是goto语句的等价物还是经常被编译器所使用具体形式是
无条件跳转指令。
当一个函数从多个位置退出并且需要做一些通用的清理工作的时候goto的好处就显现出来
了。
理由是:
- 无条件语句容易理解和跟踪
- 嵌套程度减小
- 可以避免由于修改时忘记更新某个单独的退出点而导致的错误
- 减轻了编译器的工作,无需删除冗余代码;)
int fun(int a)
{
int result = 0;
char *buffer = kmalloc(SIZE);
if (buffer == NULL)
return -ENOMEM;
if (condition1) {
while (loop1) {
...
}
result = 1;
goto out;
}
...
out:
kfree(buffer);
return result;
}
第八章:注释
注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:更好
的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。
一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把注释
放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能需要回到
第六章看一看。你可以做一些小注释来注明或警告某些很聪明(或者槽糕)的做法,但不要
加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,也可以加上它做这
些事情的原因。
当注释内核API函数时请使用kernel-doc格式。请看
Documentation/kernel-doc-nano-HOWTO.txt和scripts/kernel-doc以获得详细信息。
Linux的注释风格是C89“/* ... */”风格。不要使用C99风格“// ...”注释。
长(多行)的首选注释风格是:
/*
* 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.
*/
注释数据也是很重要的,不管是基本类型还是衍生类型。为了方便实现这一点,每一行应只
声明一个数据(不要使用逗号来一次声明多个数据)。这样你就有空间来为每个数据写一段
小注释来解释它们的用途了。
第九章:你已经把事情弄糟了
这没什么我们都是这样。可能你的使用了很长时间Unix的朋友已经告诉你“GNU emacs”能
自动帮你格式化C源代码而且你也注意到了确实是这样不过它所使用的默认值和我们
想要的相去甚远实际上甚至比随机打的还要差——无数个猴子在GNU emacs里打字永远不
会创造出一个好程序译注请参考Infinite Monkey Theorem
所以你要么放弃GNU emacs要么改变它让它使用更合理的设定。要采用后一个方案你可
以把下面这段粘贴到你的.emacs文件里。
(defun linux-c-mode ()
"C mode with adjusted defaults for use with the Linux kernel."
(interactive)
(c-mode)
(c-set-style "K&R")
(setq tab-width 8)
(setq indent-tabs-mode t)
(setq c-basic-offset 8))
这样就定义了M-x linux-c-mode命令。当你hack一个模块的时候如果你把字符串
-*- linux-c -*-放在头两行的某个位置,这个模式将会被自动调用。如果你希望在你修改
/usr/src/linux里的文件时魔术般自动打开linux-c-mode的话你也可能需要添加
(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]$" . linux-c-mode)
auto-mode-alist))
到你的.emacs文件里。
不过就算你尝试让emacs正确的格式化代码失败了也并不意味着你失去了一切还可以用“
indent”。
不过GNU indent也有和GNU emacs一样有问题的设定所以你需要给它一些命令选项。不
这还不算太糟糕因为就算是GNU indent的作者也认同K&R的权威性GNU的人并不是坏
他们只是在这个问题上被严重的误导了所以你只要给indent指定选项“-kr -i8”
代表“K&R8个字符缩进”或者使用“scripts/Lindent”这样就可以以最时髦的方式
缩进源代码。
“indent”有很多选项特别是重新格式化注释的时候你可能需要看一下它的手册页。不过
记住“indent”不能修正坏的编程习惯。
第十章Kconfig配置文件
对于遍布源码树的所有Kconfig*配置文件来说它们缩进方式与C代码相比有所不同。紧挨
在“config”定义下面的行缩进一个制表符帮助信息则再多缩进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.
仍然被认为不够稳定的功能应该被定义为依赖于“EXPERIMENTAL”
config SLUB
depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT
bool "SLUB (Unqueued Allocator)"
...
而那些危险的功能(比如某些文件系统的写支持)应该在它们的提示字符串里显著的声明这
一点:
config ADFS_FS_RW
bool "ADFS write support (DANGEROUS)"
depends on ADFS_FS
...
要查看配置文件的完整文档请看Documentation/kbuild/kconfig-language.txt。
第十一章:数据结构
如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引用计
数器。内核里没有垃圾收集(并且内核之外的垃圾收集慢且效率低下),这意味着你绝对需
要记录你对这种数据结构的使用情况。
引用计数意味着你能够避免上锁,并且允许多个用户并行访问这个数据结构——而不需要担心
这个数据结构仅仅因为暂时不被使用就消失了,那些用户可能不过是沉睡了一阵或者做了一
些其他事情而已。
注意上锁不能取代引用计数。上锁是为了保持数据结构的一致性,而引用计数是一个内存管
理技巧。通常二者都需要,不要把两个搞混了。
很多数据结构实际上有2级引用计数它们通常有不同“类”的用户。子类计数器统计子类用
户的数量,每当子类计数器减至零时,全局计数器减一。
这种“多级引用计数”的例子可以在内存管理“struct mm_struct”mm_users和mm_count
和文件系统“struct super_block”s_count和s_active中找到。
记住:如果另一个执行线索可以找到你的数据结构,但是这个数据结构没有引用计数器,这
里几乎肯定是一个bug。
第十二章枚举和RTL
用于定义常量的宏的名字及枚举里的标签需要大写。
#define CONSTANT 0x12345
在定义几个相关的常量时,最好用枚举。
宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。
一般的,如果能写成内联函数就不要写成像函数的宏。
含有多个语句的宏应该被包含在一个do-while代码块里
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
使用宏的时候应避免的事情:
1) 影响控制流程的宏:
#define FOO(x) \
do { \
if (blah(x) < 0) \
return -EBUGGERED; \
} while(0)
非常不好。它看起来像一个函数,不过却能导致“调用”它的函数退出;不要打乱读者大脑里
的语法分析器。
2) 依赖于一个固定名字的本地变量的宏:
#define FOO(val) bar(index, val)
可能看起来像是个不错的东西,不过它非常容易把读代码的人搞糊涂,而且容易导致看起来
不相关的改动带来错误。
3) 作为左值的带参数的宏: FOO(x) = y如果有人把FOO变成一个内联函数的话这种用
法就会出错了。
4) 忘记了优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内。带参数的
宏也要注意此类问题。
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
cpp手册对宏的讲解很详细。Gcc internals手册也详细讲解了RTL译注register
transfer language内核里的汇编语言经常用到它。
第十三章:打印内核消息
内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。不要
用不规范的单词比如“dont”而要用“do not”或者“don't”。保证这些信息简单、明了、无
歧义。
内核信息不必以句号(译注:英文句号,即点)结束。
在小括号里打印数字(%d)没有任何价值,应该避免这样做。
<linux/device.h>里有一些驱动模型诊断宏,你应该使用它们,以确保信息对应于正确的
设备和驱动并且被标记了正确的消息级别。这些宏有dev_err(), dev_warn(),
dev_info()等等。对于那些不和某个特定设备相关连的信息,<linux/kernel.h>定义了
pr_debug()和pr_info()。
写出好的调试信息可以是一个很大的挑战;当你写出来之后,这些信息在远程除错的时候
就会成为极大的帮助。当DEBUG符号没有被定义的时候这些信息不应该被编译进内核里
也就是说默认地它们不应该被包含在内。如果你使用dev_dbg()或者pr_debug()
就能自动达到这个效果。很多子系统拥有Kconfig选项来启用-DDEBUG。还有一个相关的惯例
是使用VERBOSE_DEBUG来添加dev_vdbg()消息到那些已经由DEBUG启用的消息之上。
第十四章:分配内存
内核提供了下面的一般用途的内存分配函数kmalloc()kzalloc()kcalloc()和
vmalloc()。请参考API文档以获取有关它们的详细信息。
传递结构体大小的首选形式是这样的:
p = kmalloc(sizeof(*p), ...);
另外一种传递方式中sizeof的操作数是结构体的名字这样会降低可读性并且可能会引
入bug。有可能指针变量类型被改变时而对应的传递给内存分配函数的sizeof的结果不变。
强制转换一个void指针返回值是多余的。C语言本身保证了从void指针到其他任何指针类型
的转换是没有问题的。
第十五章:内联弊病
有一个常见的误解是内联函数是gcc提供的可以让代码运行更快的一个选项。虽然使用内联
函数有时候是恰当的(比如作为一种替代宏的方式,请看第十二章),不过很多情况下不是
这样。inline关键字的过度使用会使内核变大从而使整个系统运行速度变慢。因为大内核
会占用更多的指令高速缓存(译注:一级缓存通常是指令缓存和数据缓存分开的)而且会导
致pagecache的可用内存减少。想象一下一次pagecache未命中就会导致一次磁盘寻址
耗时5毫秒。5毫秒的时间内CPU能执行很多很多指令。
一个基本的原则是如果一个函数有3行以上就不要把它变成内联函数。这个原则的一个例
外是,如果你知道某个参数是一个编译时常量,而且因为这个常量你确定编译器在编译时能
优化掉你的函数的大部分代码那仍然可以给它加上inline关键字。kmalloc()内联函数就
是一个很好的例子。
人们经常主张给static的而且只用了一次的函数加上inline如此不会有任何损失因为没
有什么好权衡的。虽然从技术上说这是正确的但是实际上这种情况下即使不加inline gcc
也可以自动使其内联。而且其他用户可能会要求移除inline由此而来的争论会抵消inline
自身的潜在价值,得不偿失。
第十六章:函数返回值及命名
函数可以返回很多种不同类型的值,最常见的一种是表明函数执行成功或者失败的值。这样
的一个值可以表示为一个错误代码整数(-Exxx失败0成功或者一个“成功”布尔值
0失败非0成功
混合使用这两种表达方式是难于发现的bug的来源。如果C语言本身严格区分整形和布尔型变
那么编译器就能够帮我们发现这些错误……不过C语言不区分。为了避免产生这种bug
遵循下面的惯例:
如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代码整
数。如果是一个判断,那么函数应该返回一个“成功”布尔值。
比如“add work”是一个命令所以add_work()函数在成功时返回0在失败时返回-EBUSY。
类似的因为“PCI device present”是一个判断所以pci_dev_present()函数在成功找到
一个匹配的设备时应该返回1如果找不到时应该返回0。
所有导出译注EXPORT的函数都必须遵守这个惯例所有的公共函数也都应该如此。私
static函数不需要如此但是我们也推荐这样做。
返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,他们
通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,他们使用
NULL或者ERR_PTR机制来报告错误。
第十七章:不要重新发明内核宏
头文件include/linux/kernel.h包含了一些宏你应该使用它们而不要自己写一些它们的
变种。比如,如果你需要计算一个数组的长度,使用这个宏
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
类似的,如果你要计算某结构体成员的大小,使用
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
还有可以做严格的类型检查的min()和max()宏,如果你需要可以使用它们。你可以自己看看
那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应在你的代码里
自己重新定义。
第十八章:编辑器模式行和其他需要罗嗦的事情
有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如emacs
能够解释被标记成这样的行:
-*- mode: c -*-
或者这样的:
/*
Local Variables:
compile-command: "gcc -DMAGIC_DEBUG_FLAG foo.c"
End:
*/
Vim能够解释这样的标记
/* vim:set sw=8 noet */
不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不应
该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制的模
式,或者使用其他可以产生正确的缩进的巧妙方法。
附录 I参考
The C Programming Language, 第二版, 作者Brian W. Kernighan和Denni
M. Ritchie. Prentice Hall, Inc., 1988. ISBN 0-13-110362-8 (软皮),
0-13-110370-9 (硬皮). URL: http://cm.bell-labs.com/cm/cs/cbook/
The Practice of Programming 作者Brian W. Kernighan和Rob Pike. Addison-Wesley,
Inc., 1999. ISBN 0-201-61586-X. URL: http://cm.bell-labs.com/cm/cs/tpop/
cppgccgcc internals和indent的GNU手册——和K&R及本文相符合的部分全部可以在
http://www.gnu.org/manual/找到
WG14是C语言的国际标准化工作组URL: http://www.open-std.org/JTC1/SC22/WG14/
Kernel CodingStyle作者greg@kroah.com发表于OLS 2002
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--
最后更新于2007年7月13日。

View File

@@ -0,0 +1,538 @@
Chinese translated version of Documentation/HOWTO
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Greg Kroah-Hartman <greg@kroah.com>
Chinese maintainer: Li Yang <leoli@freescale.com>
---------------------------------------------------------------------
Documentation/HOWTO 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 李阳 Li Yang <leoli@freescale.com>
中文版翻译者: 李阳 Li Yang <leoli@freescale.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 C89标准但也用到了一些
标准中没有定义的扩展。内核是自给自足的C环境不依赖于标准C库的支持所以
并不支持C标准中的部分定义。比如long long类型的大数除法和浮点运算就不允许
使用。有时候确实很难弄清楚内核对工具链的要求和它所使用的扩展,不幸的是目
前还没有明确的参考资料可以解释它们。请查阅gcc信息页使用“info gcc”命令
显示)获得一些这方面信息。
请记住你是在学习怎么和已经存在的开发社区打交道。它由一群形形色色的人组成,
他们对代码、风格和过程有着很高的标准。这些标准是在长期实践中总结出来的,
适应于地理上分散的大型开发团队。它们已经被很好得整理成档,建议你在开发
之前尽可能多的学习这些标准,而不要期望别人来适应你或者你公司的行为方式。
法律问题
--------
Linux内核源代码都是在GPL通用公共许可证的保护下发布的。要了解这种许可
的细节请查看源代码主目录下的COPYING文件。如果你对它还有更深入问题请联系
律师而不要在Linux内核邮件组上提问。因为邮件组里的人并不是律师不要期
望他们的话有法律效力。
对于GPL的常见问题和解答请访问以下链接
http://www.gnu.org/licenses/gpl-faq.html
文档
----
Linux内核代码中包含有大量的文档。这些文档对于学习如何与内核社区互动有着
不可估量的价值。当一个新的功能被加入内核,最好把解释如何使用这个功能的文
档也放进内核。当内核的改动导致面向用户空间的接口发生变化时,最好将相关信
息或手册页(manpages)的补丁发到mtk.manpages@gmail.com以向手册页(manpages)
的维护者解释这些变化。
以下是内核代码中需要阅读的文档:
README
文件简要介绍了Linux内核的背景并且描述了如何配置和编译内核。内核的
新用户应该从这里开始。
Documentation/Changes
文件给出了用来编译和使用内核所需要的最小软件包列表。
Documentation/CodingStyle
描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格
的代码。
Documentation/SubmittingPatches
Documentation/SubmittingDrivers
这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于)
- 邮件内容
- 邮件格式
- 选择收件人
遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格
审查),但是忽视他们几乎就意味着失败。
其他关于如何正确地生成补丁的优秀文档包括:
"The Perfect Patch"
http://userweb.kernel.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html
Documentation/stable_api_nonsense.txt
论证内核为什么特意不包括稳定的内核内部API也就是说不包括像这样的特
性:
- 子系统中间层(为了兼容性?)
- 在不同操作系统间易于移植的驱动程序
- 减缓(甚至阻止)内核代码的快速变化
这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
统转移到Linux的人来说也很重要。
Documentation/SecurityBugs
如果你认为自己发现了Linux内核的安全性问题请根据这篇文档中的步骤来
提醒其他内核开发者并帮助解决这个问题。
Documentation/ManagementStyle
描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对
它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的
普遍误解与迷惑。
Documentation/stable_kernel_rules.txt
解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。
Documentation/kernel-docs.txt
有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
的内容,可以查看这些文档。
Documentation/applying-patches.txt
关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍
内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何
妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内
核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册
页等不同格式的文档:
make pdfdocs
make psdocs
make htmldocs
make mandocs
如何成为内核开发者
------------------
如果你对Linux内核开发一无所知你应该访问“Linux内核新手”计划
http://kernelnewbies.org
它拥有一个可以问各种最基本的内核开发问题的邮件列表(在提问之前一定要记得
查找已往的邮件,确认是否有人已经回答过相同的问题)。它还拥有一个可以获得
实时反馈的IRC聊天频道以及大量对于学习Linux内核开发相当有帮助的文档。
网站简要介绍了源代码组织结构、子系统划分以及目前正在进行的项目(包括内核
中的和单独维护的)。它还提供了一些基本的帮助信息,比如如何编译内核和打补
丁。
如果你想加入内核开发社区并协助完成一些任务,却找不到从哪里开始,可以访问
“Linux内核房管员”计划
http://kernelnewbies.org/KernelJanitors
这是极佳的起点。它提供一个相对简单的任务列表,列出内核代码中需要被重新
整理或者改正的地方。通过和负责这个计划的开发者们一同工作,你会学到将补丁
集成进内核的基本原理。如果还没有决定下一步要做什么的话,你还可能会得到方
向性的指点。
如果你已经有一些现成的代码想要放到内核中,但是需要一些帮助来使它们拥有正
确的格式。请访问“内核导师”计划。这个计划就是用来帮助你完成这个目标的。它
是一个邮件列表,地址如下:
http://selenic.com/mailman/listinfo/kernel-mentors
在真正动手修改内核代码之前,理解要修改的代码如何运作是必需的。要达到这个
目的,没什么办法比直接读代码更有效了(大多数花招都会有相应的注释),而且
一些特制的工具还可以提供帮助。例如“Linux代码交叉引用”项目就是一个值得
特别推荐的帮助工具,它将源代码显示在有编目和索引的网页上。其中一个更新及
时的内核源码库,可以通过以下地址访问:
http://sosdg.org/~coywolf/lxr/
开发流程
--------
目前Linux内核开发流程包括几个“主内核分支”和很多子系统相关的内核分支。这
些分支包括:
- 2.6.x主内核源码树
- 2.6.x.y -stable内核源码树
- 2.6.x -git内核补丁集
- 2.6.x -mm内核补丁集
- 子系统相关的内核源码树和补丁集
2.6.x内核主源码树
-----------------
2.6.x内核是由Linus TorvaldsLinux的创造者亲自维护的。你可以在
kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步
骤:
- 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
维护者可以向Linus提交大段的修改通常这些修改已经被放到-mm内核中几个
星期了。提交大量修改的首选方式是使用git工具内核的代码版本管理工具
更多的信息可以在http://git.or.cz/获取),不过使用普通补丁也是可以
的。
- 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
可能在-rc1后被接受是因为这样的修改完全独立不会影响其他的代码所以
没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁不过所
有的补丁需要同时被发送到相应的公众邮件列表以征询意见。
- 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试
时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
- 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
6个星期。
- 以下地址跟踪了在每个-rc发布中发现的退步列表
http://kernelnewbies.org/known_regressions
关于内核发布值得一提的是Andrew Morton在linux-kernel邮件列表中如是说
“没有人知道新内核何时会被发布因为发布是根据已知bug的情况来决定
的,而不是根据一个事先制定好的时间表。”
2.6.x.y -stable稳定版内核源码树
-----------------------------------
由4个数字组成的内核版本号说明此内核是-stable版本。它们包含基于2.6.x版本
内核的相对较小且至关重要的修补,这些修补针对安全性问题或者严重的内核退步。
这种版本的内核适用于那些期望获得最新的稳定版内核并且不想参与测试开发版或
者实验版的用户。
如果没有2.6.x.y版本内核存在那么最新的2.6.x版本内核就相当于是当前的稳定
版内核。
2.6.x.y版本由“稳定版”小组邮件地址<stable@kernel.org>)维护,一般隔周发
布新版本。
内核源码中的Documentation/stable_kernel_rules.txt文件具体描述了可被稳定
版内核接受的修改类型以及发布的流程。
2.6.x -git补丁集
----------------
Linus的内核源码树的每日快照这个源码树是由git工具管理的由此得名。这
些补丁通常每天更新以反映Linus的源码树的最新状态。它们比-rc版本的内核源码
树更具试验性质,因为这个补丁集是全自动生成的,没有任何人来确认其是否真正
健全。
2.6.x -mm补丁集
---------------
这是由Andrew Morton维护的试验性内核补丁集。Andrew将所有子系统的内核源码
和补丁拼凑到一起并且加入了大量从linux-kernel邮件列表中采集的补丁。这个
源码树是新功能和补丁的试炼场。当补丁在-mm补丁集里证明了其价值以后Andrew
或者相应子系统的维护者会将补丁发给Linus以便集成进主内核源码树。
在将所有新补丁发给Linus以集成到主内核源码树之前我们非常鼓励先把这些补
丁放在-mm版内核源码树中进行测试。
这些内核版本不适合在需要稳定运行的系统上运行,因为运行它们比运行任何其他
内核分支都更具有风险。
如果你想为内核开发进程提供帮助,请尝试并使用这些内核版本,并在
linux-kernel邮件列表中提供反馈告诉大家你遇到了问题还是一切正常。
通常-mm版补丁集不光包括这些额外的试验性补丁还包括发布时-git版主源码树
中的改动。
-mm版内核没有固定的发布周期但是通常在每两个-rc版内核发布之间都会有若干
个-mm版内核发布一般是1至3个
子系统相关内核源码树和补丁集
----------------------------
相当一部分内核子系统开发者会公开他们自己的开发源码树,以便其他人能了解内
核的不同领域正在发生的事情。如上所述,这些源码树会被集成到-mm版本内核中。
下面是目前可用的一些内核源码树的列表:
通过git管理的源码树
- Kbuild开发源码树 Sam Ravnborg <sam@ravnborg.org>
git.kernel.org:/pub/scm/linux/kernel/git/sam/kbuild.git
- ACPI开发源码树, Len Brown <len.brown@intel.com>
git.kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
- 块设备开发源码树, Jens Axboe <axboe@suse.de>
git.kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
- DRM开发源码树, Dave Airlie <airlied@linux.ie>
git.kernel.org:/pub/scm/linux/kernel/git/airlied/drm-2.6.git
- ia64开发源码树, Tony Luck <tony.luck@intel.com>
git.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git
- ieee1394开发源码树, Jody McIntyre <scjody@modernduck.com>
git.kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
- infiniband开发源码树, Roland Dreier <rolandd@cisco.com>
git.kernel.org:/pub/scm/linux/kernel/git/roland/infiniband.git
- libata开发源码树, Jeff Garzik <jgarzik@pobox.com>
git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
- 网络驱动程序开发源码树, Jeff Garzik <jgarzik@pobox.com>
git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
- pcmcia开发源码树, Dominik Brodowski <linux@dominikbrodowski.net>
git.kernel.org:/pub/scm/linux/kernel/git/brodo/pcmcia-2.6.git
- SCSI开发源码树, James Bottomley <James.Bottomley@SteelEye.com>
git.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6.git
使用quilt管理的补丁集
- USB, PCI, 驱动程序核心和I2C, Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
- x86-64, 部分i386, Andi Kleen <ak@suse.de>
ftp.firstfloor.org:/pub/ak/x86_64/quilt/
其他内核源码树可以在http://git.kernel.org的列表中和MAINTAINERS文件里
找到。
报告bug
-------
bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。我们鼓励用
户在这个工具中报告找到的所有bug。如何使用内核bugzilla的细节请访问
http://test.kernel.org/bugzilla/faq.html
内核源码主目录中的REPORTING-BUGS文件里有一个很好的模板。它指导用户如何报
告可能的内核bug以及需要提供哪些信息来帮助内核开发者们找到问题的根源。
利用bug报告
-----------
练习内核开发技能的最好办法就是修改其他人报告的bug。你不光可以帮助内核变
得更加稳定,还可以学会如何解决实际问题从而提高自己的技能,并且让其他开发
者感受到你的存在。修改bug是赢得其他开发者赞誉的最好办法因为并不是很多
人都喜欢浪费时间去修改别人报告的bug。
要尝试修改已知的bug请访问http://bugzilla.kernel.org网址。如果你想获得
最新bug的通知可以订阅bugme-new邮件列表只有新的bug报告会被寄到这里
或者订阅bugme-janitor邮件列表所有bugzilla的变动都会被寄到这里
https://lists.linux-foundation.org/mailman/listinfo/bugme-new
https://lists.linux-foundation.org/mailman/listinfo/bugme-janitors
邮件列表
--------
正如上面的文档所描述大多数的骨干内核开发者都加入了Linux Kernel邮件列
表。如何订阅和退订列表的细节可以在这里找到:
http://vger.kernel.org/vger-lists.html#linux-kernel
网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些
存档。比如:
http://dir.gmane.org/gmane.linux.kernel
在发信之前,我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细
讨论过的问题只在邮件列表的存档中可以找到。
大多数内核子系统也有自己独立的邮件列表来协调各自的开发工作。从
MAINTAINERS文件中可以找到不同话题对应的邮件列表。
很多邮件列表架设在kernel.org服务器上。这些列表的信息可以在这里找到
http://vger.kernel.org/vger-lists.html
在使用这些邮件列表时,请记住保持良好的行为习惯。下面的链接提供了与这些列
表(或任何其它邮件列表)交流的一些简单规则,虽然内容有点滥竽充数。
http://www.albion.com/netiquette/
当有很多人回复你的邮件时,邮件的抄送列表会变得很长。请不要将任何人从抄送
列表中删除,除非你有足够的理由这么做。也不要只回复到邮件列表。请习惯于同
一封邮件接收两次(一封来自发送者一封来自邮件列表),而不要试图通过添加一
些奇特的邮件头来解决这个问题,人们不会喜欢的。
记住保留你所回复内容的上下文和源头。在你回复邮件的顶部保留“某某某说到……”
这几行。将你的评论加在被引用的段落之间而不要放在邮件的顶部。
如果你在邮件中附带补丁,请确认它们是可以直接阅读的纯文本(如
Documentation/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”
http://userweb.kernel.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>

View File

@@ -0,0 +1,50 @@
Chinese translated version of Documentation/SecurityBugs
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/SecurityBugs 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
以下为正文
---------------------------------------------------------------------
Linux内核开发者认为安全非常重要。因此我们想要知道当一个有关于
安全的漏洞被发现的时候,并且它可能会被尽快的修复或者公开。请把这个安全
漏洞报告给Linux内核安全团队。
1) 联系
linux内核安全团队可以通过email<security@kernel.org>来联系。这是
一组独立的安全工作人员,可以帮助改善漏洞报告并且公布和取消一个修复。安
全团队有可能会从部分的维护者那里引进额外的帮助来了解并且修复安全漏洞。
当遇到任何漏洞,所能提供的信息越多就越能诊断和修复。如果你不清楚什么
是有帮助的信息那就请重温一下REPORTING-BUGS文件中的概述过程。任
何攻击性的代码都是非常有用的,未经报告者的同意不会被取消,除非它已经
被公布于众。
2) 公开
Linux内核安全团队的宗旨就是和漏洞提交者一起处理漏洞的解决方案直
到公开。我们喜欢尽快地完全公开漏洞。当一个漏洞或者修复还没有被完全地理
解,解决方案没有通过测试或者供应商协调,可以合理地延迟公开。然而,我们
期望这些延迟尽可能的短些,是可数的几天,而不是几个星期或者几个月。公开
日期是通过安全团队和漏洞提供者以及供应商洽谈后的结果。公开时间表是从很
短(特殊的,它已经被公众所知道)到几个星期。作为一个基本的默认政策,我
们所期望通知公众的日期是7天的安排。
3) 保密协议
Linux内核安全团队不是一个正式的团体因此不能加入任何的保密协议。

View File

@@ -0,0 +1,168 @@
Chinese translated version of Documentation/SubmittingDrivers
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Li Yang <leo@zh-kernel.org>
---------------------------------------------------------------------
Documentation/SubmittingDrivers 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
张巍 Zhang Wei <Wei.Zhang@freescale.com>
以下为正文
---------------------------------------------------------------------
如何向 Linux 内核提交驱动程序
-----------------------------
这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(http://www.xfree86.org/)
和/或 X.org 项目 (http://x.org)。
另请参阅 Documentation/SubmittingPatches 文档。
分配设备号
----------
块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA
现在是 Torben Mathiasen负责分配。申请的网址是 http://www.lanana.org/。
即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
请参阅 Documentation/devices.txt。
如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
设备驱动的提交对象
------------------
Linux 2.0:
此内核源码树不接受新的驱动程序。
Linux 2.2:
此内核源码树不接受新的驱动程序。
Linux 2.4:
如果所属的代码领域在内核的 MAINTAINERS 文件中列有一个总维护者,
那么请将驱动程序提交给他。如果此维护者没有回应或者你找不到恰当的
维护者,那么请联系 Willy Tarreau <w@1wt.eu>。
Linux 2.6:
除了遵循和 2.4 版内核同样的规则外,你还需要在 linux-kernel 邮件
列表上跟踪最新的 API 变化。向 Linux 2.6 内核提交驱动的顶级联系人
是 Andrew Morton <akpm@linux-foundation.org>。
决定设备驱动能否被接受的条件
----------------------------
许可: 代码必须使用 GNU 通用公开许可证 (GPL) 提交给 Linux但是
我们并不要求 GPL 是唯一的许可。你或许会希望同时使用多种
许可证发布如果希望驱动程序可以被其他开源社区比如BSD
使用。请参考 include/linux/module.h 文件中所列出的可被
接受共存的许可。
版权: 版权所有者必须同意使用 GPL 许可。最好提交者和版权所有者
是相同个人或实体。否则,必需列出授权使用 GPL 的版权所有
人或实体,以备验证之需。
接口: 如果你的驱动程序使用现成的接口并且和其他同类的驱动程序行
为相似,而不是去发明无谓的新接口,那么它将会更容易被接受。
如果你需要一个 Linux 和 NT 的通用驱动接口,那么请在用
户空间实现它。
代码: 请使用 Documentation/CodingStyle 中所描述的 Linux 代码风
格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
享的代码段)需要使用其他格式,而你却只希望维护一份代码,
那么请将它们很好地区分出来,并且注明原因。
可移植性: 请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
可以被轻松地移植却是很简单的。
清晰度: 做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
电源管理: 因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
动程序也很有可能被使用在这些设备上。它应该支持最基本的电
源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
.suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
函数定义成返回 -ENOSYS功能未实现错误。你还应该尝试确
保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
程序测试的指导,请参阅
Documentation/power/drivers-testing.txt。有关驱动程序电
源管理问题相对全面的概述,请参阅
Documentation/power/devices.txt。
管理: 如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
好在代码注释中写明并且在 MAINTAINERS 文件中加入这个驱动
程序的条目。
不影响设备驱动能否被接受的条件
------------------------------
供应商: 由硬件供应商来维护驱动程序通常是一件好事。不过,如果源码
树里已经有其他人提供了可稳定工作的驱动程序,那么请不要期
望“我是供应商”会成为内核改用你的驱动程序的理由。理想的情
况是:供应商与现有驱动程序的作者合作,构建一个统一完美的
驱动程序。
作者: 驱动程序是由大的 Linux 公司研发还是由你个人编写,并不影
响其是否能被内核接受。没有人对内核源码树享有特权。只要你
充分了解内核社区,你就会发现这一点。
资源列表
--------
Linux 内核主源码树:
ftp.??.kernel.org:/pub/linux/kernel/...
?? == 你的国家代码,例如 "cn"、"us"、"uk"、"fr" 等等
Linux 内核邮件列表:
linux-kernel@vger.kernel.org
[可通过向majordomo@vger.kernel.org发邮件来订阅]
Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
http://lwn.net/Kernel/LDD3/ (免费版)
LWN.net:
每周内核开发活动摘要 - http://lwn.net/
2.6 版中 API 的变更:
http://lwn.net/Articles/2.6-kernel-api/
将旧版内核的驱动程序移植到 2.6 版:
http://lwn.net/Articles/driver-porting/
KernelTrap
Linux 内核的最新动态以及开发者访谈
http://kerneltrap.org/
内核新手(KernelNewbies):
为新的内核开发者提供文档和帮助
http://kernelnewbies.org/
Linux USB项目
http://www.linux-usb.org/
写内核驱动的“不要”Arjan van de Ven著:
http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
内核清洁工 (Kernel Janitor):
http://kernelnewbies.org/KernelJanitors

View File

@@ -0,0 +1,416 @@
Chinese translated version of Documentation/SubmittingPatches
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: TripleX Chung <triplex@zh-kernel.org>
---------------------------------------------------------------------
Documentation/SubmittingPatches 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
---------------------------------------------------------------------
如何让你的改动进入内核
或者
获得亲爱的 Linus Torvalds 的关注和处理
----------------------------------
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
的改动被接受的机会。
阅读 Documentation/SubmitChecklist 来获得在提交代码前需要检查的项目的列
表。如果你在提交一个驱动程序,那么同时阅读一下
Documentation/SubmittingDrivers 。
--------------------------
第一节 - 创建并发送你的改动
--------------------------
1) "diff -up"
-----------
使用 "diff -up" 或者 "diff -uprN" 来创建补丁。
所有内核的改动,都是以补丁的形式呈现的,补丁由 diff(1) 生成。创建补丁的
时候,要确认它是以 "unified diff" 格式创建的,这种格式由 diff(1) 的 '-u'
参数生成。而且,请使用 '-p' 参数那样会显示每个改动所在的C函数使得
产生的补丁容易读得多。补丁应该基于内核源代码树的根目录,而不是里边的任
何子目录。
为一个单独的文件创建补丁,一般来说这样做就够了:
SRCTREE= linux-2.6
MYFILE= drivers/net/mydriver.c
cd $SRCTREE
cp $MYFILE $MYFILE.orig
vi $MYFILE # make your change
cd ..
diff -up $SRCTREE/$MYFILE{.orig,} > /tmp/patch
为多个文件创建补丁,你可以解开一个没有修改过的内核源代码树,然后和你自
己的代码树之间做 diff 。例如:
MYSRC= /devel/linux-2.6
tar xvfz linux-2.6.12.tar.gz
mv linux-2.6.12 linux-2.6.12-vanilla
diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \
linux-2.6.12-vanilla $MYSRC > /tmp/patch
"dontdiff" 是内核在编译的时候产生的文件的列表,列表中的文件在 diff(1)
产生的补丁里会被跳过。"dontdiff" 文件被包含在2.6.12和之后版本的内核源代
码树中。对于更早的内核版本,你可以从
<http://www.xenotime.net/linux/doc/dontdiff> 获取它。
确定你的补丁里没有包含任何不属于这次补丁提交的额外文件。记得在用diff(1)
生成补丁之后,审阅一次补丁,以确保准确。
如果你的改动很散乱,你应该研究一下如何将补丁分割成独立的部分,将改动分
割成一系列合乎逻辑的步骤。这样更容易让其他内核开发者审核,如果你想你的
补丁被接受,这是很重要的。下面这些脚本能够帮助你做这件事情:
Quilt:
http://savannah.nongnu.org/projects/quilt
Andrew Morton 的补丁脚本:
http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
作为这些脚本的替代quilt 是值得推荐的补丁管理工具(看上面的链接)。
2)描述你的改动。
描述你的改动包含的技术细节。
要多具体就写多具体。最糟糕的描述可能是像下面这些语句:“更新了某驱动程
序”“修正了某驱动程序的bug”或者“这个补丁包含了某子系统的修改
使用。”
如果你的描述开始变长这表示你也许需要拆分你的补丁了请看第3小节
继续。
3)拆分你的改动
将改动拆分,逻辑类似的放到同一个补丁文件里。
例如如果你的改动里同时有bug修正和性能优化那么把这些改动拆分到两个或
者更多的补丁文件中。如果你的改动包含对API的修改并且修改了驱动程序来适
应这些新的API那么把这些修改分成两个补丁。
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
丁描述里指出“这个补丁依赖某补丁”就好了。
如果你不能将补丁浓缩成更少的文件那么每次大约发送出15个然后等待审查
和整合。
4)选择 e-mail 的收件人
看一遍 MAINTAINERS 文件和源代码,看看你所的改动所在的内核子系统有没有指
定的维护者。如果有给他们发e-mail。
如果没有找到维护者,或者维护者没有反馈,将你的补丁发送到内核开发者主邮
件列表 linux-kernel@vger.kernel.org。大部分的内核开发者都跟踪这个邮件列
表,可以评价你的改动。
每次不要发送超过15个补丁到 vger 邮件列表!!!
Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
的说,最好别给他发 e-mail。
那些修正bug“显而易见”的修改或者是类似的只需要很少讨论的补丁可以直接
发送或者CC给Linus。那些需要讨论或者没有很清楚的好处的补丁一般先发送到
linux-kernel邮件列表。只有当补丁被讨论得差不多了才提交给Linus。
5)选择CC( e-mail 抄送)列表
除非你有理由不这样做否则CC linux-kernel@vger.kernel.org。
除了 Linus 之外,其他内核开发者也需要注意到你的改动,这样他们才能评论你
的改动并提供代码审查和建议。linux-kernel 是 Linux 内核开发者主邮件列表
。其它的邮件列表为特定的子系统提供服务,比如 USBframebuffer 设备,虚
拟文件系统SCSI 子系统,等等。查看 MAINTAINERS 文件来获得和你的改动有
关的邮件列表。
Majordomo lists of VGER.KERNEL.ORG at:
<http://vger.kernel.org/vger-lists.html>
如果改动影响了用户空间和内核之间的接口,请给 MAN-PAGES 的维护者(列在
MAITAINERS 文件里的发送一个手册页man-pages补丁或者至少通知一下改
变,让一些信息有途径进入手册页。
即使在第四步的时候,维护者没有作出回应,也要确认在修改他们的代码的时候
一直将维护者拷贝到CC列表中。
对于小的补丁你也许会CC到 Adrian Bunk 管理的搜集琐碎补丁的邮件列表
(Trivial Patch Monkey)trivial@kernel.org那里专门收集琐碎的补丁。下面这样
的补丁会被看作“琐碎的”补丁:
文档的拼写修正。
修正会影响到 grep(1) 的拼写。
警告信息修正(频繁的打印无用的警告是不好的。)
编译错误修正(代码逻辑的确是对的,只是编译有问题。)
运行时修正(只要真的修正了错误。)
移除使用了被废弃的函数/宏的代码(例如 check_region。)
联系方式和文档修正。
用可移植的代码替换不可移植的代码(即使在体系结构相关的代码中,既然有
人拷贝,只要它是琐碎的)
任何文件的作者/维护者对该文件的改动(例如 patch monkey 在重传模式下)
EMAIL: trivial@kernel.org
(译注,关于“琐碎补丁”的一些说明:因为原文的这一部分写得比较简单,所以不得不
违例写一下译注。"trivial"这个英文单词的本意是“琐碎的,不重要的。”但是在这里
有稍微有一些变化例如对一些明显的NULL指针的修正属于运行时修正会被归类
到琐碎补丁里。虽然NULL指针的修正很重要但是这样的修正往往很小而且很容易得到
检验,所以也被归入琐碎补丁。琐碎补丁更精确的归类应该是
“simple, localized & easy to verify”也就是说简单的局部的和易于检验的。
trivial@kernel.org邮件列表的目的是针对这样的补丁为提交者提供一个中心
降低提交的门槛。)
6)没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本。
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
代码的任何位置添加评论。
因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
警告:如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的
补丁。
不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
代码中加评论。另外MIME 编码的附件会让 Linus 多花一点时间来处理,这就
降低了你的改动被接受的可能性。
警告:一些邮件软件,比如 Mozilla 会将你的信息以如下格式发送:
---- 邮件头 ----
Content-Type: text/plain; charset=us-ascii; format=flowed
---- 邮件头 ----
问题在于 “format=flowed” 会让接收端的某些邮件软件将邮件中的制表符替换
成空格以及做一些类似的替换。这样,你发送的时候看起来没问题的补丁就被破
坏了。
要修正这个问题,只需要将你的 mozilla 的 defaults/pref/mailnews.js 文件
里的
pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
修改成
pref("mailnews.display.disable_format_flowed_support", true);
就可以了。
7) e-mail 的大小
给 Linus 发送补丁的时候永远按照第6小节说的做。
大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
的情况下超过了40kB那么你最好将补丁放在一个能通过 internet 访问的服
务器上,然后用指向你的补丁的 URL 替代。
8) 指出你的内核版本
在标题和在补丁的描述中,指出补丁对应的内核的版本,是很重要的。
如果补丁不能干净的在最新版本的内核上打上Linus 是不会接受它的。
9) 不要气馁,继续提交。
当你提交了改动以后,耐心地等待。如果 Linus 喜欢你的改动并且同意它,那么
它将在下一个内核发布版本中出现。
然而,如果你的改动没有出现在下一个版本的内核中,可能有若干原因。减少那
些原因,修正错误,重新提交更新后的改动,是你自己的工作。
Linus不给出任何评论就“丢弃”你的补丁是常见的事情。在系统中这样的事情很
平常。如果他没有接受你的补丁,也许是由于以下原因:
* 你的补丁不能在最新版本的内核上干净的打上。
* 你的补丁在 linux-kernel 邮件列表中没有得到充分的讨论。
* 风格问题参照第2小节
* 邮件格式问题(重读本节)
* 你的改动有技术问题。
* 他收到了成吨的 e-mail而你的在混乱中丢失了。
* 你让人为难。
有疑问的时候,在 linux-kernel 邮件列表上请求评论。
10) 在标题上加上 PATCH 的字样
Linus 和 linux-kernel 邮件列表的 e-mail 流量都很高,一个通常的约定是标
题行以 [PATCH] 开头。这样可以让 Linus 和其他内核开发人员可以从 e-mail
的讨论中很轻易的将补丁分辨出来。
11为你的工作签名
为了加强对谁做了何事的追踪,尤其是对那些透过好几层的维护者的补丁,我们
建议在发送出去的补丁上加一个 “sign-off” 的过程。
"sign-off" 是在补丁的注释的最后的简单的一行文字,认证你编写了它或者其他
人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息
开发者来源证书 1.1
对于本项目的贡献,我认证如下信息:
a这些贡献是完全或者部分的由我创建我有权利以文件中指出
的开放源代码许可证提交它;或者
b这些贡献基于以前的工作据我所知这些以前的工作受恰当的开放
源代码许可证保护,而且,根据许可证,我有权提交修改后的贡献,
无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
(除非我被允许用其它的许可证),正如文件中指出的;或者
c这些贡献由认证ab或者c的人直接提供给我
且我没有修改它。
d我理解并同意这个项目和贡献是公开的贡献的记录包括我
一起提交的个人记录,包括 sign-off )被永久维护并且可以和这个项目
或者开放源代码的许可证同步地再发行。
那么加入这样一行:
Signed-off-by: Random J Developer <random@developer.example.org>
使用你的真名(抱歉,不能使用假名或者匿名。)
有人在最后加上标签。现在这些东西会被忽略,但是你可以这样做,来标记公司
内部的过程,或者只是指出关于 sign-off 的一些特殊细节。
12标准补丁格式
标准的补丁,标题行是:
Subject: [PATCH 001/123] 子系统:一句话概述
标准补丁的信体存在如下部分:
- 一个 "from" 行指出补丁作者。
- 一个空行
- 说明的主体,这些说明文字会被拷贝到描述该补丁的永久改动记录里。
- 一个由"---"构成的标记行
- 不合适放到改动记录里的额外的注解。
- 补丁本身diff 输出)
标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
丁),不要对每个补丁都使用同样的“一句话概述”。
记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
章。
一些标题的例子:
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCHv2 001/207] x86: fix eflags tracking
"from" 行是信体里的最上面一行,具有如下格式:
From: Original Author <author@example.com>
"from" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "from" 行,那
么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
这个补丁相关的讨论细节的有能力的读者来说,是有意义的。
"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
的。
对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat用来显
示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
动日志里的,也应该放这里。
使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
不会占用太宽的空间很容易适合80列的宽度也许会有一些缩进。
在后面的参考资料中能看到适当的补丁格式的更多细节。
-------------------------------
第二节 提示,建议和诀窍
-------------------------------
本节包含很多和提交到内核的代码有关的通常的"规则"。事情永远有例外...但是
你必须真的有好的理由这样做。你可以把本节叫做Linus的计算机科学入门课。
1) 读 Document/CodingStyle
Nuff 说过,如果你的代码和这个偏离太多,那么它有可能会被拒绝,没有更多的
审查,没有更多的评价。
2) #ifdef 是丑陋的
混杂了 ifdef 的代码难以阅读和维护。别这样做。作为替代,将你的 ifdef 放
在头文件里,有条件地定义 "static inline" 函数,或者宏,在代码里用这些东
西。让编译器把那些"空操作"优化掉。
一个简单的例子,不好的代码:
dev = alloc_etherdev (sizeof(struct funky_private));
if (!dev)
return -ENODEV;
#ifdef CONFIG_NET_FUNKINESS
init_funky_net(dev);
#endif
清理后的例子:
(头文件里)
#ifndef CONFIG_NET_FUNKINESS
static inline void init_funky_net (struct net_device *d) {}
#endif
(代码文件里)
dev = alloc_etherdev (sizeof(struct funky_private));
if (!dev)
return -ENODEV;
init_funky_net(dev);
3) 'static inline' 比宏好
Static inline 函数相比宏来说是好得多的选择。Static inline 函数提供了
类型安全,没有长度限制,没有格式限制,在 gcc 下开销和宏一样小。
宏只在 static inline 函数不是最优的时候[在 fast paths 里有很少的独立的
案例],或者不可能用 static inline 函数的时候[例如字符串分配]。
应该用 'static inline' 而不是 'static __inline__', 'extern inline' 和
'extern __inline__' 。
4) 不要过度设计
不要试图预计模糊的未来事情,这些事情也许有用也许没有用:"让事情尽可能的
简单,而不是更简单"。
----------------
第三节 参考文献
----------------
Andrew Morton, "The perfect patch" (tpp).
<http://userweb.kernel.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/2005/03/31/>
<http://www.kroah.com/log/2005/07/08/>
<http://www.kroah.com/log/2005/10/19/>
<http://www.kroah.com/log/2006/01/11/>
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
<http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
Kernel Documentation/CodingStyle:
<http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
Linus Torvalds's mail on the canonical patch format:
<http://lkml.org/lkml/2005/4/7/183>
--

View File

@@ -0,0 +1,210 @@
Chinese translated version of Documentation/email-clients.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/email-clients.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版校译者: Yinglin Luan <synmyth@gmail.com>
Xiaochen Wang <wangxiaochen0@gmail.com>
yaxinsn <yaxinsn@163.com>
以下为正文
---------------------------------------------------------------------
Linux邮件客户端配置信息
======================================================================
普通配置
----------------------------------------------------------------------
Linux内核补丁是通过邮件被提交的最好把补丁作为邮件体的内嵌文本。有些维护者
接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的,
因为这会使补丁的引用部分在评论过程中变的很困难。
用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如
他们不能改变或者删除制表符或者空格,甚至是在每一行的开头或者结尾。
不要通过"format=flowed"模式发送补丁。这样会引起不可预期以及有害的断行。
不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。
邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码方式
如果你使用UTF-8编码方式发送邮件那么你将会避免一些可能发生的字符集问题。
邮件客户端应该形成并且保持 References: 或者 In-Reply-To: 标题,那么
邮件话题就不会中断。
复制粘帖(或者剪贴粘帖)通常不能用于补丁因为制表符会转换为空格。使用xclipboard, xclip
或者xcutsel也许可以但是最好测试一下或者避免使用复制粘帖。
不要在使用PGP/GPG署名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的补丁。
(这个问题应该是可以修复的)
在给内核邮件列表发送补丁之前,给自己发送一个补丁是个不错的主意,保存接收到的
邮件,将补丁用'patch'命令打上,如果成功了,再给内核邮件列表发送。
一些邮件客户端提示
----------------------------------------------------------------------
这里给出一些详细的MUA配置提示可以用于给Linux内核发送补丁。这些并不意味是
所有的软件包配置总结。
说明:
TUI = 以文本为基础的用户接口
GUI = 图形界面用户接口
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Alpine (TUI)
配置选项:
在"Sending Preferences"部分:
- "Do Not Send Flowed Text"必须开启
- "Strip Whitespace Before Sending"必须关闭
当写邮件时光标应该放在补丁会出现的地方然后按下CTRL-R组合键使指定的
补丁文件嵌入到邮件中。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Evolution (GUI)
一些开发者成功的使用它发送补丁
当选择邮件选项Preformat
从Format->Heading->Preformatted (Ctrl-7)或者工具栏
然后使用:
Insert->Text File... (Alt-n x)插入补丁文件。
你还可以"diff -Nru old.c new.c | xclip"选择Preformat然后使用中间键进行粘帖。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kmail (GUI)
一些开发者成功的使用它发送补丁。
默认设置不为HTML格式是合适的不要启用它。
当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输入的任何文本
都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法就是启用自动换行来书写邮件,
然后把它保存为草稿。一旦你在草稿中再次打开它,它已经全部自动换行了,那么你的邮件虽然没有
选择自动换行,但是还不会失去已有的自动换行。
在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字号(---)。
然后在"Message"菜单条目,选择插入文件,接着选取你的补丁文件。还有一个额外的选项,你可以
通过它配置你的邮件建立工具栏菜单,还可以带上"insert file"图标。
你可以安全地通过GPG标记附件但是内嵌补丁最好不要使用GPG标记它们。作为内嵌文本的签发补丁
当从GPG中提取7位编码时会使他们变的更加复杂。
如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选中属性,突出"Suggest automatic
display",这样内嵌附件更容易让读者看到。
当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然后右击选择
"save as"。你可以使用一个没有更改的包含补丁的邮件,如果它是以正确的形式组成。当你正真在它
自己的窗口之下察看,那时没有选项可以保存邮件--已经有一个这样的bug被汇报到了kmail的bugzilla
并且希望这将会被处理。邮件是以只针对某个用户可读写的权限被保存的,所以如果你想把邮件复制到其他地方,
你不得不把他们的权限改为组或者整体可读。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lotus Notes (GUI)
不要使用它。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mutt (TUI)
很多Linux开发人员使用mutt客户端所以证明它肯定工作的非常漂亮。
Mutt不自带编辑器所以不管你使用什么编辑器都不应该带有自动断行。大多数编辑器都带有
一个"insert file"选项,它可以通过不改变文件内容的方式插入文件。
'vim'作为mutt的编辑器
set editor="vi"
如果使用xclip敲入以下命令
:set paste
按中键之前或者shift-insert或者使用
:r filename
如果想要把补丁作为内嵌文本。
(a)ttach工作的很好不带有"set paste"。
配置选项:
它应该以默认设置的形式工作。
然而,把"send_charset"设置为"us-ascii::utf-8"也是一个不错的主意。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pine (TUI)
Pine过去有一些空格删减问题但是这些现在应该都被修复了。
如果可以请使用alpine(pine的继承者)
配置选项:
- 最近的版本需要消除流程文本
- "no-strip-whitespace-before-send"选项也是需要的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sylpheed (GUI)
- 内嵌文本可以很好的工作(或者使用附件)。
- 允许使用外部的编辑器。
- 对于目录较多时非常慢。
- 如果通过non-SSL连接无法使用TLS SMTP授权。
- 在组成窗口中有一个很有用的ruler bar。
- 给地址本中添加地址就不会正确的了解显示名。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thunderbird (GUI)
默认情况下thunderbird很容易损坏文本但是还有一些方法可以强制它变得更好。
- 在用户帐号设置里,组成和寻址,不要选择"Compose messages in HTML format"。
- 编辑你的Thunderbird配置设置来使它不要拆行使用user_pref("mailnews.wraplength", 0);
- 编辑你的Thunderbird配置设置使它不要使用"format=flowed"格式user_pref("mailnews.
send_plaintext_flowed", false);
- 你需要使Thunderbird变为预先格式方式
如果默认情况下你书写的是HTML格式那不是很难。仅仅从标题栏的下拉框中选择"Preformat"格式。
如果默认情况下你书写的是文本格式你不得把它改为HTML格式仅仅作为一次性的来书写新的消息
然后强制使它回到文本格式否则它就会拆行。要实现它在写信的图标上使用shift键来使它变为HTML
格式,然后标题栏的下拉框中选择"Preformat"格式。
- 允许使用外部的编辑器:
针对Thunderbird打补丁最简单的方法就是使用一个"external editor"扩展,然后使用你最喜欢的
$EDITOR来读取或者合并补丁到文本中。要实现它可以下载并且安装这个扩展然后添加一个使用它的
按键View->Toolbars->Customize...最后当你书写信息的时候仅仅点击它就可以了。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TkRat (GUI)
可以使用它。使用"Insert file..."或者外部的编辑器。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Gmail (Web GUI)
不要使用它发送补丁。
Gmail网页客户端自动地把制表符转换为空格。
虽然制表符转换为空格问题可以被外部编辑器解决同时它还会使用回车换行把每行拆分为78个字符。
另一个问题是Gmail还会把任何不是ASCII的字符的信息改为base64编码。它把东西变的像欧洲人的名字。
###

View File

@@ -0,0 +1,167 @@
Chinese translated version of Documentation/magic-number.txt
If you have any comment or update to the content, please post to LKML directly.
However, if you have problem communicating in English you can also ask the
Chinese maintainer for help. Contact the Chinese maintainer, if this
translation is outdated or there is problem with translation.
Chinese maintainer: Jia Wei Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/magic-number.txt的中文翻译
如果想评论或更新本文的内容请直接发信到LKML。如果你使用英文交流有困难的话也可
以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。
中文版维护者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
以下为正文
---------------------------------------------------------------------
这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。
使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(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
CMAGIC 0x0111 user include/linux/a.out.h
MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h
RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h
SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h
HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c
APM_BIOS_MAGIC 0x4101 apm_user arch/x86/kernel/apm_32.c
CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h
DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c
DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c
FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h
FF_MAGIC 0x4646 fc_info drivers/net/iph5526_novram.c
ISICOM_MAGIC 0x4d54 isi_port include/linux/isicom.h
PTY_MAGIC 0x5001 drivers/char/pty.c
PPP_MAGIC 0x5002 ppp include/linux/if_pppvar.h
SERIAL_MAGIC 0x5301 async_struct include/linux/serial.h
SSTATE_MAGIC 0x5302 serial_state include/linux/serial.h
SLIP_MAGIC 0x5302 slip drivers/net/slip.h
STRIP_MAGIC 0x5303 strip drivers/net/strip.c
X25_ASY_MAGIC 0x5303 x25_asy drivers/net/x25_asy.h
SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h
AX25_MAGIC 0x5316 ax_disp drivers/net/mkiss.h
ESP_MAGIC 0x53ee esp_struct drivers/char/esp.h
TTY_MAGIC 0x5401 tty_struct include/linux/tty.h
MGSL_MAGIC 0x5401 mgsl_info drivers/char/synclink.c
TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h
MGSLPC_MAGIC 0x5402 mgslpc_info drivers/char/pcmcia/synclink_cs.c
TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h
USB_SERIAL_MAGIC 0x6702 usb_serial drivers/usb/serial/usb-serial.h
FULL_DUPLEX_MAGIC 0x6969 drivers/net/ethernet/dec/tulip/de2104x.c
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c
RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h
CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h
A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h
RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h
LSEMAGIC 0x05091998 lse drivers/fc4/fc.c
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h
RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c
RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c
SX_MAGIC 0x12345678 gs_port drivers/char/sx.h
NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h
RED_MAGIC2 0x170fc2a5 (any) mm/slab.c
BAYCOM_MAGIC 0x19730510 baycom_state drivers/net/baycom_epp.c
ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data
drivers/isdn/isdn_x25iface.h
ECP_MAGIC 0x21504345 cdkecpsig include/linux/cdk.h
LSOMAGIC 0x27091997 lso drivers/fc4/fc.c
LSMAGIC 0x2a3b4d2a ls drivers/fc4/fc.c
WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} include/linux/wanpipe.h
CS_CARD_MAGIC 0x43525553 cs_card sound/oss/cs46xx.c
LABELCL_MAGIC 0x4857434c labelcl_info_s include/asm/ia64/sn/labelcl.h
ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h
CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info drivers/s390/net/ctctty.c
ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_lib.h
SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c
STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h
CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c
SLAB_C_MAGIC 0x4f17a36d kmem_cache mm/slab.c
COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c
I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c
TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c
ROUTER_MAGIC 0x524d4157 wan_device include/linux/wanrouter.h
SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h
SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda arch/mips/include/asm/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
KV_MAGIC 0x5f4b565f kernel_vars_s arch/mips/include/asm/sn/klkernvars.h
I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c
TRIDENT_STATE_MAGIC 0x63657373 trient_state sound/oss/trident.c
M3_CARD_MAGIC 0x646e6f50 m3_card sound/oss/maestro3.c
FW_HEADER_MAGIC 0x65726F66 fw_header drivers/atm/fore200e.h
SLOT_MAGIC 0x67267321 slot drivers/hotplug/cpqphp.h
SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h
LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h
OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h
M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c
STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h
VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c
KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h
ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.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
HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c
NMI_MAGIC 0x48414d4d455201 nmi_s arch/mips/include/asm/sn/nmi.h
请注意在声音记忆管理中仍然有每一些被定义的驱动魔术值。查看include/sound/sndmagic.h来获取他们完整的列表信息。很多OSS声音驱动拥有自己从声卡PCI ID构建的魔术值-他们也没有被列在这里。
IrDA子系统也使用了大量的自己的魔术值查看include/net/irda/irda.h来获取他们完整的信息。
HFS是另外一个比较大的使用魔术值的文件系统-你可以在fs/hfs/hfs.h中找到他们。

View File

@@ -0,0 +1,212 @@
Chinese translated version of Documentation/oops-tracing.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Dave Young <hidave.darkstar@gmail.com>
---------------------------------------------------------------------
Documentation/oops-tracing.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
---------------------------------------------------------------------
注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg等等)。
忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
ksymoops的来自2.6的Oops人们只会让你重贴一次。
快速总结
-------------
发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
价值。
如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
尽可能地稳定。
Oops在哪里?
----------------------
通常Oops文本由klogd从内核缓冲区里读取并传给syslogd由syslogd写到syslog文件中
典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
cat /proc/kmsg > file 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-
1 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
息滚动到了终端的上面你会发现以高分辩率启动比如vga=791会让你读到更多的文
本。注意这需要vesafb所以对早期的oops没有帮助
2用串口终端启动请参看Documentation/serial-console.txt运行一个null
modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
3使用Kdump请参看Documentation/kdump/kdump.txt
使用在Documentation/kdump/gdbmacros.txt中定义的dmesg gdb宏从旧的内存中提取内核
环形缓冲区。
完整信息
----------------
注意以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
一些信息仍然适用。 特别注意的是请忽略任何ksymoops的引用。
From: Linus Torvalds <torvalds@osdl.org>
怎样跟踪Oops.. [原发到linux-kernel的一封邮件]
主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)
实际上,你有办法使它更简单。我有两个不同的方法:
gdb /usr/src/linux/vmlinux
gdb> disassemble <offending_function>
那是发现问题的简单办法至少如果bug报告做的好的情况下象这个一样-运行ksymoops
得到oops发生的函数及函数内的偏移
哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。
另一件要做的事是反汇编bug报告的“Code”部分ksymoops也会用正确的工具来做这件事
但如果没有那些工具你可以写一个傻程序:
char str[] = "\xXX\xXX\xXX...";
main(){}
并用gcc -g编译它然后执行“disassemble str”XX部分是由Oops报告的值-你可以仅剪切
粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。
另外你可以用scripts/decodecode这个shell脚本。它的使用方法是
decodecode < oops.txt
“Code”之后的十六进制字节可能在某些架构上有一些当前指令之前的指令字节以及
当前和之后的指令字节
Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
最后,如果你想知道代码来自哪里,你可以:
cd /usr/src/linux
make fs/buffer.s # 或任何产生BUG的文件
然后你会比gdb反汇编更清楚的知道发生了什么。
现在问题是把你所拥有的所有数据结合起来C源码关于它应该怎样的一般知识
汇编代码及其反汇编得到的代码另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
指针有用而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
)。
实际上你仅需看看哪里不匹配这个例子是“Code”反汇编和编译器生成的代码不匹配
然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
空指针是怎么出现的,还有检查它是否合法..
现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
仅仅是找出正确的序列也确实需要相当扎实的内核知识)
_有时_会发生这种情况我仅看到崩溃中的反汇编代码序列 然后我马上就明白问题出在
哪里。这时我才意识到自己干这个工作已经太长时间了;-)
Linus
---------------------------------------------------------------------------
关于Oops跟踪的注解
为了帮助Linus和其它内核开发者klogd纳入了大量的支持来处理保护错误。为了拥有对
地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。
当保护错误发生时klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
号。
klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
map文件。关于klogd怎样搜索map文件请参看klogd手册页。
动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。
内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。
至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
以从模块中输出符号信息。
因为内核模块环境可能是动态的所以必须有一种机制当模块环境发生改变时来通知klogd
守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号告知符
号信息应该被刷新了。 更多信息请参看klogd手册页。
sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
错误的无缝支持。
以下是被klogd处理过的发生在可装载模块中的一个保护错误例子
---------------------------------------------------------------------------
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
Aug 29 09:51:01 blizard kernel: *pde = 00000000
Aug 29 09:51:01 blizard kernel: Oops: 0002
Aug 29 09:51:01 blizard kernel: CPU: 0
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
---------------------------------------------------------------------------
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
820 4th St. N.
Fargo, ND 58122
Phone: 701-234-7556
---------------------------------------------------------------------------
受污染的内核
一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。
1'G'如果所有装载的模块都有GPL或相容的许可证'P'如果装载了任何的专有模块。
没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
认定是专有的。
2'F'如果有任何通过“insmod -f”被强制装载的模块' '如果所有模块都被正常装载。
3'S'如果oops发生在SMP内核中运行于没有证明安全运行多处理器的硬件。 当前这种
情况仅限于几种不支持SMP的速龙处理器。
4'R'如果模块通过“insmod -f”被强制装载' '如果所有模块都被正常装载。
5'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。
6'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。
7'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。
8'D'如果内核刚刚死掉比如有OOPS或者BUG。
使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
以表明内核不再值得信任。

View File

@@ -0,0 +1,100 @@
Chinese translated version of Documentation/sparse.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: Li Yang <leo@zh-kernel.org>
---------------------------------------------------------------------
Documentation/sparse.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
以下为正文
---------------------------------------------------------------------
Copyright 2004 Linus Torvalds
Copyright 2004 Pavel Machek <pavel@ucw.cz>
Copyright 2006 Bob Copeland <me@bobcopeland.com>
使用 sparse 工具做类型检查
~~~~~~~~~~~~~~~~~~~~~~~~~~
"__bitwise" 是一种类型属性,所以你应该这样使用它:
typedef int __bitwise pm_request_t;
enum pm_request {
PM_SUSPEND = (__force pm_request_t) 1,
PM_RESUME = (__force pm_request_t) 2
};
这样会使 PM_SUSPEND 和 PM_RESUME 成为位方式(bitwise)整数(使用"__force"
是因为 sparse 会抱怨改变位方式的类型转换,但是这里我们确实需要强制进行转
换)。而且因为所有枚举值都使用了相同的类型,这里的"enum pm_request"也将
会使用那个类型做为底层实现。
而且使用 gcc 编译的时候,所有的 __bitwise/__force 都会消失,最后在 gcc
看来它们只不过是普通的整数。
坦白来说,你并不需要使用枚举类型。上面那些实际都可以浓缩成一个特殊的"int
__bitwise"类型。
所以更简单的办法只要这样做:
typedef int __bitwise pm_request_t;
#define PM_SUSPEND ((__force pm_request_t) 1)
#define PM_RESUME ((__force pm_request_t) 2)
现在你就有了严格的类型检查所需要的所有基础架构。
一个小提醒:常数整数"0"是特殊的。你可以直接把常数零当作位方式整数使用而
不用担心 sparse 会抱怨。这是因为"bitwise"(恰如其名)是用来确保不同位方
式类型不会被弄混小尾模式大尾模式cpu尾模式或者其他对他们来说
常数"0"确实是特殊的。
获取 sparse 工具
~~~~~~~~~~~~~~~~
你可以从 Sparse 的主页获取最新的发布版本:
http://www.kernel.org/pub/linux/kernel/people/josh/sparse/
或者,你也可以使用 git 克隆最新的 sparse 开发版本:
git://git.kernel.org/pub/scm/linux/kernel/git/josh/sparse.git
DaveJ 把每小时自动生成的 git 源码树 tar 包放在以下地址:
http://www.codemonkey.org.uk/projects/git-snapshots/sparse/
一旦你下载了源码,只要以普通用户身份运行:
make
make install
它将会被自动安装到你的 ~/bin 目录下。
使用 sparse 工具
~~~~~~~~~~~~~~~~
用"make C=1"命令来编译内核,会对所有重新编译的 C 文件使用 sparse 工具。
或者使用"make C=2"命令,无论文件是否被重新编译都会对其使用 sparse 工具。
如果你已经编译了内核,用后一种方式可以很快地检查整个源码树。
make 的可选变量 CHECKFLAGS 可以用来向 sparse 工具传递参数。编译系统会自
动向 sparse 工具传递 -Wbitwise 参数。你可以定义 __CHECK_ENDIAN__ 来进行
大小尾检查。
make C=2 CHECKFLAGS="-D__CHECK_ENDIAN__"
这些检查默认都是被关闭的,因为他们通常会产生大量的警告。

View File

@@ -0,0 +1,157 @@
Chinese translated version of Documentation/stable_api_nonsense.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have problem
communicating in English you can also ask the Chinese maintainer for help.
Contact the Chinese maintainer, if this translation is outdated or there
is problem with translation.
Maintainer: Greg Kroah-Hartman <greg@kroah.com>
Chinese maintainer: TripleX Chung <zhongyu@18mail.cn>
---------------------------------------------------------------------
Documentation/stable_api_nonsense.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版翻译者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版校译者: 李阳 Li Yang <leoli@freescale.com>
以下为正文
---------------------------------------------------------------------
写作本文档的目的是为了解释为什么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>

View File

@@ -0,0 +1,66 @@
Chinese translated version of Documentation/stable_kernel_rules.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Chinese maintainer: TripleX Chung <triplex@zh-kernel.org>
---------------------------------------------------------------------
Documentation/stable_kernel_rules.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
Kangkai Yin <e12051@motorola.com>
以下为正文
---------------------------------------------------------------------
关于Linux 2.6稳定版发布,所有你想知道的事情。
关于哪些类型的补丁可以被接收进入稳定版代码树,哪些不可以的规则:
- 必须是显而易见的正确,并且经过测试的。
- 连同上下文不能大于100行。
- 必须只修正一件事情。
- 必须修正了一个给大家带来麻烦的真正的bug不是“这也许是一个问题...”
那样的东西)。
- 必须修正带来如下后果的问题编译错误对被标记为CONFIG_BROKEN的例外
内核崩溃,挂起,数据损坏,真正的安全问题,或者一些类似“哦,这不
好”的问题。简短的说,就是一些致命的问题。
- 没有“理论上的竞争条件”,除非能给出竞争条件如何被利用的解释。
- 不能存在任何的“琐碎的”修正(拼写修正,去掉多余空格之类的)。
- 必须被相关子系统的维护者接受。
- 必须遵循Documentation/SubmittingPatches里的规则。
向稳定版代码树提交补丁的过程:
- 在确认了补丁符合以上的规则后将补丁发送到stable@kernel.org。
- 如果补丁被接受到队列里发送者会收到一个ACK回复如果没有被接受
到的是NAK回复。回复需要几天的时间这取决于开发者的时间安排。
- 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
- 安全方面的补丁不要发到这个列表应该发送到security@kernel.org。
审查周期:
- 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
到linux-kernel邮件列表。
- 审查委员会有48小时的时间用来决定给该补丁回复ACK还是NAK。
- 如果委员会中有成员拒绝这个补丁或者linux-kernel列表上有人反对这个
补丁,并提出维护者和审查委员会之前没有意识到的问题,补丁会从队列中
丢弃。
- 在审查周期结束的时候那些得到ACK回应的补丁将会被加入到最新的稳定版
发布中,一个新的稳定版发布就此产生。
- 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中,而不是通过
通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
审查委员会:
- 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。

View File

@@ -0,0 +1,113 @@
Chinese translated version of Documentation/volatile-considered-harmful.txt
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
Maintainer: Jonathan Corbet <corbet@lwn.net>
Chinese maintainer: Bryan Wu <bryan.wu@analog.com>
---------------------------------------------------------------------
Documentation/volatile-considered-harmful.txt 的中文翻译
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
英文版维护者: Jonathan Corbet <corbet@lwn.net>
中文版维护者: 伍鹏 Bryan Wu <bryan.wu@analog.com>
中文版翻译者: 伍鹏 Bryan Wu <bryan.wu@analog.com>
中文版校译者: 张汉辉 Eugene Teo <eugeneteo@kernel.sg>
杨瑞 Dave Young <hidave.darkstar@gmail.com>
以下为正文
---------------------------------------------------------------------
为什么不应该使用“volatile”类型
------------------------------
C程序员通常认为volatile表示某个变量可以在当前执行的线程之外被改变因此在内核
中用到共享数据结构时常常会有C程序员喜欢使用volatile这类变量。换句话说他们经
常会把volatile类型看成某种简易的原子变量当然它们不是。在内核中使用volatile几
乎总是错误的;本文档将解释为什么这样。
理解volatile的关键是知道它的目的是用来消除优化实际上很少有人真正需要这样的应
用。在内核中,程序员必须防止意外的并发访问破坏共享的数据结构,这其实是一个完全
不同的任务。用来防止意外并发访问的保护措施,可以更加高效的避免大多数优化相关的
问题。
像volatile一样内核提供了很多原语来保证并发访问时的数据安全自旋锁, 互斥量,内
存屏障等等),同样可以防止意外的优化。如果可以正确使用这些内核原语,那么就没有
必要再使用volatile。如果仍然必须使用volatile那么几乎可以肯定在代码的某处有一
个bug。在正确设计的内核代码中volatile能带来的仅仅是使事情变慢。
思考一下这段典型的内核代码:
spin_lock(&the_lock);
do_something_on(&shared_data);
do_something_else_with(&shared_data);
spin_unlock(&the_lock);
如果所有的代码都遵循加锁规则当持有the_lock的时候不可能意外的改变shared_data的
值。任何可能访问该数据的其他代码都会在这个锁上等待。自旋锁原语跟内存屏障一样—— 它
们显式的用来书写成这样 —— 意味着数据访问不会跨越它们而被优化。所以本来编译器认为
它知道在shared_data里面将有什么但是因为spin_lock()调用跟内存屏障一样,会强制编
译器忘记它所知道的一切。那么在访问这些数据时不会有优化的问题。
如果shared_data被声名为volatile锁操作将仍然是必须的。就算我们知道没有其他人正在
使用它编译器也将被阻止优化对临界区内shared_data的访问。在锁有效的同时
shared_data不是volatile的。在处理共享数据的时候适当的锁操作可以不再需要
volatile —— 并且是有潜在危害的。
volatile的存储类型最初是为那些内存映射的I/O寄存器而定义。在内核里寄存器访问也应
该被锁保护但是人们也不希望编译器“优化”临界区内的寄存器访问。内核里I/O的内存访问
是通过访问函数完成的不赞成通过指针对I/O内存的直接访问并且不是在所有体系架构上
都能工作。那些访问函数正是为了防止意外优化而写的因此再说一次volatile类型不
是必需的。
另一种引起用户可能使用volatile的情况是当处理器正忙着等待一个变量的值。正确执行一
个忙等待的方法是:
while (my_variable != what_i_want)
cpu_relax();
cpu_relax()调用会降低CPU的能量消耗或者让位于超线程双处理器它也作为内存屏障一样出
所以再一次volatile不是必需的。当然忙等待一开始就是一种反常规的做法。
在内核中一些稀少的情况下volatile仍然是有意义的
- 在一些体系架构的系统上允许直接的I/0内存访问那么前面提到的访问函数可以使用
volatile。基本上每一个访问函数调用它自己都是一个小的临界区域并且保证了按照
程序员期望的那样发生访问操作。
- 某些会改变内存的内联汇编代码虽然没有什么其他明显的附作用但是有被GCC删除的可
能性。在汇编声明中加上volatile关键字可以防止这种删除操作。
- Jiffies变量是一种特殊情况虽然每次引用它的时候都可以有不同的值但读jiffies
变量时不需要任何特殊的加锁保护。所以jiffies变量可以使用volatile但是不赞成
其他跟jiffies相同类型变量使用volatile。Jiffies被认为是一种“愚蠢的遗留物"
Linus的话因为解决这个问题比保持现状要麻烦的多。
- 由于某些I/0设备可能会修改连续一致的内存,所以有时,指向连续一致内存的数据结构
的指针需要正确的使用volatile。网络适配器使用的环状缓存区正是这类情形的一个例
子,其中适配器用改变指针来表示哪些描述符已经处理过了。
对于大多代码上述几种可以使用volatile的情况都不适用。所以使用volatile是一种
bug并且需要对这样的代码额外仔细检查。那些试图使用volatile的开发人员需要退一步想想
他们真正想实现的是什么。
非常欢迎删除volatile变量的补丁 只要证明这些补丁完整的考虑了并发问题。
注释
----
[1] http://lwn.net/Articles/233481/
[2] http://lwn.net/Articles/233482/
致谢
----
最初由Randy Dunlap推动并作初步研究
由Jonathan Corbet撰写
参考Satyam SharmaJohannes StezenbachJesper JuhlHeikki Orsila
H. Peter AnvinPhilipp Hahn和Stefan Richter的意见改善了本档。