+++ /dev/null
-Chinese translated version of Documentation/process/howto.rst
-
-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/process/howto.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-英文版维护者: 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/process/changes.rst
- 文件给出了用来编译和使用内核所需要的最小软件包列表。
-
- Documentation/process/coding-style.rst
- 描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
- 范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格
- 的代码。
-
- Documentation/process/submitting-patches.rst
- Documentation/process/submitting-drivers.rst
- 这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
- - 邮件内容
- - 邮件格式
- - 选择收件人
- 遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格
- 审查),但是忽视他们几乎就意味着失败。
-
- 其他关于如何正确地生成补丁的优秀文档包括:
- "The Perfect Patch"
- http://www.ozlabs.org/~akpm/stuff/tpp.txt
- "Linux kernel patch submission format"
- http://linux.yyz.us/patch-format.html
-
- Documentation/process/stable-api-nonsense.rst
- 论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特
- 性:
- - 子系统中间层(为了兼容性?)
- - 在不同操作系统间易于移植的驱动程序
- - 减缓(甚至阻止)内核代码的快速变化
- 这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
- 统转移到Linux的人来说也很重要。
-
- Documentation/admin-guide/security-bugs.rst
- 如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来
- 提醒其他内核开发者并帮助解决这个问题。
-
- Documentation/process/management-style.rst
- 描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对
- 它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的
- 普遍误解与迷惑。
-
- Documentation/process/stable-kernel-rules.rst
- 解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。
-
- Documentation/process/kernel-docs.rst
- 有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
- 的内容,可以查看这些文档。
-
- Documentation/process/applying-patches.rst
- 关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍
-
-内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何
-妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内
-核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册
-页等不同格式的文档:
- make pdfdocs
- make htmldocs
-
-
-如何成为内核开发者
-------------------
-如果你对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 -mm内核补丁集
- - 子系统相关的内核源码树和补丁集
-
-
-2.6.x内核主源码树
------------------
-2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你可以在
-kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步
-骤:
- - 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
- 维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个
- 星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具
- ,更多的信息可以在http://git-scm.com/获取),不过使用普通补丁也是可以
- 的。
- - 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
- 新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
- 可能在-rc1后被接受是因为这样的修改完全独立,不会影响其他的代码,所以
- 没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁,不过所
- 有的补丁需要同时被发送到相应的公众邮件列表以征询意见。
- - 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试
- 时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
- - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
- 6个星期。
-
-关于内核发布,值得一提的是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@vger.kernel.org>)维护,一般隔周发
-布新版本。
-
-内核源码中的Documentation/process/stable-kernel-rules.rst文件具体描述了可被稳定
-版内核接受的修改类型以及发布的流程。
-
-
-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
-
-内核源码主目录中的admin-guide/reporting-bugs.rst文件里有一个很好的模板。它指导用户如何报
-告可能的内核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/process/submitting-patches.rst文档中所述)。内核开发者们不希望遇到附件
-或者被压缩了的补丁。只有这样才能保证他们可以直接评论你的每行代码。请确保
-你使用的邮件发送程序不会修改空格和制表符。一个防范性的测试方法是先将邮件
-发送给自己,然后自己尝试是否可以顺利地打上收到的补丁。如果测试不成功,请
-调整或者更换你的邮件发送程序直到它正确工作为止。
-
-总而言之,请尊重其他的邮件列表订阅者。
-
-
-同内核社区合作
-----------------
-
-内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的
-时候,它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢?
- - 批评
- - 评论
- - 要求修改
- - 要求证明修改的必要性
- - 沉默
-
-要记住,这些是把补丁放进内核的正常情况。你必须学会听取对补丁的批评和评论,
-从技术层面评估它们,然后要么重写你的补丁要么简明扼要地论证修改是不必要
-的。如果你发的邮件没有得到任何回应,请过几天后再试一次,因为有时信件会湮
-没在茫茫信海中。
-
-你不应该做的事情:
- - 期望自己的补丁不受任何质疑就直接被接受
- - 翻脸
- - 忽略别人的评论
- - 没有按照别人的要求做任何修改就重新提交
-
-在一个努力追寻最好技术方案的社区里,对于一个补丁有多少好处总会有不同的见
-解。你必须要抱着合作的态度,愿意改变自己的观点来适应内核的风格。或者至少
-愿意去证明你的想法是有价值的。记住,犯错误是允许的,只要你愿意朝着正确的
-方案去努力。
-
-如果你的第一个补丁换来的是一堆修改建议,这是很正常的。这并不代表你的补丁
-不会被接受,也不意味着有人和你作对。你只需要改正所有提出的问题然后重新发
-送你的补丁。
-
-内核社区和公司文化的差异
-------------------------
-
-内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
-子,可以帮助你避免某些可能发生问题:
- 用这些话介绍你的修改提案会有好处:
- - 它同时解决了多个问题
- - 它删除了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://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>
+++ /dev/null
-Chinese translated version of Documentation/process/submitting-drivers.rst
-
-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/process/submitting-drivers.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 李阳 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/process/submitting-patches.rst 文档。
-
-
-分配设备号
-----------
-
-块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
-现在是 Torben Mathiasen)负责分配。申请的网址是 http://www.lanana.org/。
-即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
-请参阅 Documentation/admin-guide/devices.rst。
-
-如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
-制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
-
-设备驱动的提交对象
-------------------
-
-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/process/coding-style.rst 中所描述的 Linux 代码风
- 格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
- 享的代码段)需要使用其他格式,而你却只希望维护一份代码,
- 那么请将它们很好地区分出来,并且注明原因。
-
-可移植性: 请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
- 尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
- 单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
- x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
- 硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
- 可以被轻松地移植却是很简单的。
-
-清晰度: 做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
- 会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
- 隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
-
-电源管理: 因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
- 动程序也很有可能被使用在这些设备上。它应该支持最基本的电
- 源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
- .suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
- 确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
- 函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
- 保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
- 程序测试的指导,请参阅
- Documentation/power/drivers-testing.txt。有关驱动程序电
- 源管理问题相对全面的概述,请参阅
- Documentation/driver-api/pm/devices.rst。
-
-管理: 如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
- 些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
- 被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
- 好在代码注释中写明并且在 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/
-
-内核新手(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
+++ /dev/null
-Chinese translated version of Documentation/process/submitting-patches.rst
-
-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/process/submitting-patches.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 钟宇 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/process/submit-checklist.rst 来获得在提交代码前需要检查的项目的列
-表。如果你在提交一个驱动程序,那么同时阅读一下
-Documentation/process/submitting-drivers.rst 。
-
-
---------------------------
-第一节 - 创建并发送你的改动
---------------------------
-
-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
-
-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 内核开发者主邮件列表
-。其它的邮件列表为特定的子系统提供服务,比如 USB,framebuffer 设备,虚
-拟文件系统,SCSI 子系统,等等。查看 MAINTAINERS 文件来获得和你的改动有
-关的邮件列表。
-
-Majordomo lists of VGER.KERNEL.ORG at:
- <http://vger.kernel.org/vger-lists.html>
-
-如果改动影响了用户空间和内核之间的接口,请给 MAN-PAGES 的维护者(列在
-MAINTAINERS 文件里的)发送一个手册页(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)这些贡献由认证(a),(b)或者(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/process/coding-style.rst
-
-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://www.ozlabs.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!
- <https://lkml.org/lkml/2005/7/11/336>
-
-Kernel Documentation/process/coding-style.rst:
- <http://sosdg.org/~coywolf/lxr/source/Documentation/process/coding-style.rst>
-
-Linus Torvalds's mail on the canonical patch format:
- <http://lkml.org/lkml/2005/4/7/183>
---
+++ /dev/null
-Chinese translated version of Documentation/process/coding-style.rst
-
-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/process/coding-style.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接发信到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 代码规范,然后不要读。烧了它,这是一个具有重大象征
-性意义的动作。
-
-不管怎样,现在我们开始:
-
-
-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;
- /* fall through */
- default:
- break;
- }
-
-不要把多个语句放在一行里,除非你有什么东西要隐藏:
-
-.. code-block:: c
-
- if (condition) do_this;
- do_something_everytime;
-
-也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
-的表达式。
-
-除了注释、文档和 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`` 可以用来称呼任意类型的临时变量。
-
-如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
-合症。请看第六章 (函数)。
-
-
-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);
-
-在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,在
-Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
-
-
-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/doc-guide/ 和 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:: none
-
- (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`` 不能修正坏的编程习惯。
-
-
-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.txt。
-
-
-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 调试选项来开启 -DDEBUG 在对应的 Makefile 里面;在其他
-情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,
-如果已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
-
-
-14) 分配内存
-------------------------------
-
-内核提供了下面的一般用途的内存分配函数:
-kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
-请参考 API 文档以获取有关它们的详细信息。
-
-传递结构体大小的首选形式是这样的:
-
-.. 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。
-
-
-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) 不要重新发明内核宏
-------------------------------
-
-头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些
-它们的变种。比如,如果你需要计算一个数组的长度,使用这个宏
-
-.. code-block:: c
-
- #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
-类似的,如果你要计算某结构体成员的大小,使用
-
-.. code-block:: c
-
- #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
-
-还有可以做严格的类型检查的 min() 和 max() 宏,如果你需要可以使用它们。你可以
-自己看看那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应
-在你的代码里自己重新定义。
-
-
-18) 编辑器模式行和其他需要罗嗦的事情
---------------------------------------------------
-
-有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,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 */
-
-不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不
-应该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制
-的模式,或者使用其他可以产生正确的缩进的巧妙方法。
-
-
-19) 内联汇编
-------------------------------
-
-在特定架构的代码中,你可能需要内联汇编与 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 */);
-
-
-20) 条件编译
-------------------------------
-
-只要可能,就不要在 .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, 第二版
-作者:Brian W. Kernighan 和 Denni M. Ritchie.
-Prentice Hall, Inc., 1988.
-ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
-
-The Practice of Programming
-作者:Brian W. Kernighan 和 Rob Pike.
-Addison-Wesley, Inc., 1999.
-ISBN 0-201-61586-X.
-
-GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
-都可以从 http://www.gnu.org/manual/ 找到
-
-WG14 是 C 语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
-
-Kernel process/coding-style.rst,作者 greg@kroah.com 发表于 OLS 2002:
-http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
+++ /dev/null
-Chinese translated version of Documentation/process/email-clients.rst
-
-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/process/email-clients.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-中文版维护者: 贾威威 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编码。它把东西变的像欧洲人的名字。
-
- ###
+++ /dev/null
-Chinese translated version of Documentation/process/magic-number.rst
-
-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/process/magic-number.rst的中文翻译
-
-如果想评论或更新本文的内容,请直接发信到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
-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
-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
-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
-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
-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 [in wanrouter.h pre 3.9]
-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
-EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
-HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.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
-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
-ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
-CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
-DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.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中找到他们。
--- /dev/null
+Chinese translated version of Documentation/process/howto.rst
+
+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/process/howto.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: 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/process/changes.rst
+ 文件给出了用来编译和使用内核所需要的最小软件包列表。
+
+ Documentation/process/coding-style.rst
+ 描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
+ 范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格
+ 的代码。
+
+ Documentation/process/submitting-patches.rst
+ Documentation/process/submitting-drivers.rst
+ 这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
+ - 邮件内容
+ - 邮件格式
+ - 选择收件人
+ 遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格
+ 审查),但是忽视他们几乎就意味着失败。
+
+ 其他关于如何正确地生成补丁的优秀文档包括:
+ "The Perfect Patch"
+ http://www.ozlabs.org/~akpm/stuff/tpp.txt
+ "Linux kernel patch submission format"
+ http://linux.yyz.us/patch-format.html
+
+ Documentation/process/stable-api-nonsense.rst
+ 论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特
+ 性:
+ - 子系统中间层(为了兼容性?)
+ - 在不同操作系统间易于移植的驱动程序
+ - 减缓(甚至阻止)内核代码的快速变化
+ 这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
+ 统转移到Linux的人来说也很重要。
+
+ Documentation/admin-guide/security-bugs.rst
+ 如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来
+ 提醒其他内核开发者并帮助解决这个问题。
+
+ Documentation/process/management-style.rst
+ 描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对
+ 它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的
+ 普遍误解与迷惑。
+
+ Documentation/process/stable-kernel-rules.rst
+ 解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。
+
+ Documentation/process/kernel-docs.rst
+ 有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
+ 的内容,可以查看这些文档。
+
+ Documentation/process/applying-patches.rst
+ 关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍
+
+内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何
+妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内
+核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册
+页等不同格式的文档:
+ make pdfdocs
+ make htmldocs
+
+
+如何成为内核开发者
+------------------
+如果你对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 -mm内核补丁集
+ - 子系统相关的内核源码树和补丁集
+
+
+2.6.x内核主源码树
+-----------------
+2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你可以在
+kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步
+骤:
+ - 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
+ 维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个
+ 星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具
+ ,更多的信息可以在http://git-scm.com/获取),不过使用普通补丁也是可以
+ 的。
+ - 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
+ 新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
+ 可能在-rc1后被接受是因为这样的修改完全独立,不会影响其他的代码,所以
+ 没有造成内核退步的风险。在-rc1以后也可以用git向Linus提交补丁,不过所
+ 有的补丁需要同时被发送到相应的公众邮件列表以征询意见。
+ - 当Linus认为当前的git源码树已经达到一个合理健全的状态足以发布供人测试
+ 时,一个新的-rc版本就会被发布。计划是每周都发布新的-rc版本。
+ - 这个过程一直持续下去直到内核被认为达到足够稳定的状态,持续时间大概是
+ 6个星期。
+
+关于内核发布,值得一提的是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@vger.kernel.org>)维护,一般隔周发
+布新版本。
+
+内核源码中的Documentation/process/stable-kernel-rules.rst文件具体描述了可被稳定
+版内核接受的修改类型以及发布的流程。
+
+
+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
+
+内核源码主目录中的admin-guide/reporting-bugs.rst文件里有一个很好的模板。它指导用户如何报
+告可能的内核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/process/submitting-patches.rst文档中所述)。内核开发者们不希望遇到附件
+或者被压缩了的补丁。只有这样才能保证他们可以直接评论你的每行代码。请确保
+你使用的邮件发送程序不会修改空格和制表符。一个防范性的测试方法是先将邮件
+发送给自己,然后自己尝试是否可以顺利地打上收到的补丁。如果测试不成功,请
+调整或者更换你的邮件发送程序直到它正确工作为止。
+
+总而言之,请尊重其他的邮件列表订阅者。
+
+
+同内核社区合作
+----------------
+
+内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的
+时候,它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢?
+ - 批评
+ - 评论
+ - 要求修改
+ - 要求证明修改的必要性
+ - 沉默
+
+要记住,这些是把补丁放进内核的正常情况。你必须学会听取对补丁的批评和评论,
+从技术层面评估它们,然后要么重写你的补丁要么简明扼要地论证修改是不必要
+的。如果你发的邮件没有得到任何回应,请过几天后再试一次,因为有时信件会湮
+没在茫茫信海中。
+
+你不应该做的事情:
+ - 期望自己的补丁不受任何质疑就直接被接受
+ - 翻脸
+ - 忽略别人的评论
+ - 没有按照别人的要求做任何修改就重新提交
+
+在一个努力追寻最好技术方案的社区里,对于一个补丁有多少好处总会有不同的见
+解。你必须要抱着合作的态度,愿意改变自己的观点来适应内核的风格。或者至少
+愿意去证明你的想法是有价值的。记住,犯错误是允许的,只要你愿意朝着正确的
+方案去努力。
+
+如果你的第一个补丁换来的是一堆修改建议,这是很正常的。这并不代表你的补丁
+不会被接受,也不意味着有人和你作对。你只需要改正所有提出的问题然后重新发
+送你的补丁。
+
+内核社区和公司文化的差异
+------------------------
+
+内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
+子,可以帮助你避免某些可能发生问题:
+ 用这些话介绍你的修改提案会有好处:
+ - 它同时解决了多个问题
+ - 它删除了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://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>
--- /dev/null
+Chinese translated version of Documentation/process/submitting-drivers.rst
+
+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/process/submitting-drivers.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 李阳 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/process/submitting-patches.rst 文档。
+
+
+分配设备号
+----------
+
+块设备和字符设备的主设备号与从设备号是由 Linux 命名编号分配权威 LANANA(
+现在是 Torben Mathiasen)负责分配。申请的网址是 http://www.lanana.org/。
+即使不准备提交到主流内核的设备驱动也需要在这里分配设备号。有关详细信息,
+请参阅 Documentation/admin-guide/devices.rst。
+
+如果你使用的不是已经分配的设备号,那么当你提交设备驱动的时候,它将会被强
+制分配一个新的设备号,即便这个设备号和你之前发给客户的截然不同。
+
+设备驱动的提交对象
+------------------
+
+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/process/coding-style.rst 中所描述的 Linux 代码风
+ 格。如果你的某些代码段(例如那些与 Windows 驱动程序包共
+ 享的代码段)需要使用其他格式,而你却只希望维护一份代码,
+ 那么请将它们很好地区分出来,并且注明原因。
+
+可移植性: 请注意,指针并不永远是 32 位的,不是所有的计算机都使用小
+ 尾模式 (little endian) 存储数据,不是所有的人都拥有浮点
+ 单元,不要随便在你的驱动程序里嵌入 x86 汇编指令。只能在
+ x86 上运行的驱动程序一般是不受欢迎的。虽然你可能只有 x86
+ 硬件,很难测试驱动程序在其他平台上是否可用,但是确保代码
+ 可以被轻松地移植却是很简单的。
+
+清晰度: 做到所有人都能修补这个驱动程序将会很有好处,因为这样你将
+ 会直接收到修复的补丁而不是 bug 报告。如果你提交一个试图
+ 隐藏硬件工作机理的驱动程序,那么它将会被扔进废纸篓。
+
+电源管理: 因为 Linux 正在被很多移动设备和桌面系统使用,所以你的驱
+ 动程序也很有可能被使用在这些设备上。它应该支持最基本的电
+ 源管理,即在需要的情况下实现系统级休眠和唤醒要用到的
+ .suspend 和 .resume 函数。你应该检查你的驱动程序是否能正
+ 确地处理休眠与唤醒,如果实在无法确认,请至少把 .suspend
+ 函数定义成返回 -ENOSYS(功能未实现)错误。你还应该尝试确
+ 保你的驱动在什么都不干的情况下将耗电降到最低。要获得驱动
+ 程序测试的指导,请参阅
+ Documentation/power/drivers-testing.txt。有关驱动程序电
+ 源管理问题相对全面的概述,请参阅
+ Documentation/driver-api/pm/devices.rst。
+
+管理: 如果一个驱动程序的作者还在进行有效的维护,那么通常除了那
+ 些明显正确且不需要任何检查的补丁以外,其他所有的补丁都会
+ 被转发给作者。如果你希望成为驱动程序的联系人和更新者,最
+ 好在代码注释中写明并且在 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/
+
+内核新手(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
--- /dev/null
+Chinese translated version of Documentation/process/submitting-patches.rst
+
+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/process/submitting-patches.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 钟宇 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/process/submit-checklist.rst 来获得在提交代码前需要检查的项目的列
+表。如果你在提交一个驱动程序,那么同时阅读一下
+Documentation/process/submitting-drivers.rst 。
+
+
+--------------------------
+第一节 - 创建并发送你的改动
+--------------------------
+
+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
+
+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 内核开发者主邮件列表
+。其它的邮件列表为特定的子系统提供服务,比如 USB,framebuffer 设备,虚
+拟文件系统,SCSI 子系统,等等。查看 MAINTAINERS 文件来获得和你的改动有
+关的邮件列表。
+
+Majordomo lists of VGER.KERNEL.ORG at:
+ <http://vger.kernel.org/vger-lists.html>
+
+如果改动影响了用户空间和内核之间的接口,请给 MAN-PAGES 的维护者(列在
+MAINTAINERS 文件里的)发送一个手册页(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)这些贡献由认证(a),(b)或者(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/process/coding-style.rst
+
+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://www.ozlabs.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!
+ <https://lkml.org/lkml/2005/7/11/336>
+
+Kernel Documentation/process/coding-style.rst:
+ <http://sosdg.org/~coywolf/lxr/source/Documentation/process/coding-style.rst>
+
+Linus Torvalds's mail on the canonical patch format:
+ <http://lkml.org/lkml/2005/4/7/183>
+--
--- /dev/null
+Chinese translated version of Documentation/process/coding-style.rst
+
+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/process/coding-style.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接发信到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 代码规范,然后不要读。烧了它,这是一个具有重大象征
+性意义的动作。
+
+不管怎样,现在我们开始:
+
+
+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;
+ /* fall through */
+ default:
+ break;
+ }
+
+不要把多个语句放在一行里,除非你有什么东西要隐藏:
+
+.. code-block:: c
+
+ if (condition) do_this;
+ do_something_everytime;
+
+也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
+的表达式。
+
+除了注释、文档和 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`` 可以用来称呼任意类型的临时变量。
+
+如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
+合症。请看第六章 (函数)。
+
+
+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);
+
+在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,在
+Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
+
+
+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/doc-guide/ 和 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:: none
+
+ (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`` 不能修正坏的编程习惯。
+
+
+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.txt。
+
+
+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 调试选项来开启 -DDEBUG 在对应的 Makefile 里面;在其他
+情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,
+如果已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
+
+
+14) 分配内存
+------------------------------
+
+内核提供了下面的一般用途的内存分配函数:
+kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
+请参考 API 文档以获取有关它们的详细信息。
+
+传递结构体大小的首选形式是这样的:
+
+.. 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。
+
+
+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) 不要重新发明内核宏
+------------------------------
+
+头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些
+它们的变种。比如,如果你需要计算一个数组的长度,使用这个宏
+
+.. code-block:: c
+
+ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+类似的,如果你要计算某结构体成员的大小,使用
+
+.. code-block:: c
+
+ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
+
+还有可以做严格的类型检查的 min() 和 max() 宏,如果你需要可以使用它们。你可以
+自己看看那个头文件里还定义了什么你可以拿来用的东西,如果有定义的话,你就不应
+在你的代码里自己重新定义。
+
+
+18) 编辑器模式行和其他需要罗嗦的事情
+--------------------------------------------------
+
+有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,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 */
+
+不要在源代码中包含任何这样的内容。每个人都有他自己的编辑器配置,你的源文件不
+应该覆盖别人的配置。这包括有关缩进和模式配置的标记。人们可以使用他们自己定制
+的模式,或者使用其他可以产生正确的缩进的巧妙方法。
+
+
+19) 内联汇编
+------------------------------
+
+在特定架构的代码中,你可能需要内联汇编与 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 */);
+
+
+20) 条件编译
+------------------------------
+
+只要可能,就不要在 .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, 第二版
+作者:Brian W. Kernighan 和 Denni M. Ritchie.
+Prentice Hall, Inc., 1988.
+ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
+
+The Practice of Programming
+作者:Brian W. Kernighan 和 Rob Pike.
+Addison-Wesley, Inc., 1999.
+ISBN 0-201-61586-X.
+
+GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
+都可以从 http://www.gnu.org/manual/ 找到
+
+WG14 是 C 语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
+
+Kernel process/coding-style.rst,作者 greg@kroah.com 发表于 OLS 2002:
+http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
--- /dev/null
+Chinese translated version of Documentation/process/email-clients.rst
+
+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/process/email-clients.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+中文版维护者: 贾威威 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编码。它把东西变的像欧洲人的名字。
+
+ ###
--- /dev/null
+Chinese translated version of Documentation/process/magic-number.rst
+
+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/process/magic-number.rst的中文翻译
+
+如果想评论或更新本文的内容,请直接发信到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
+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
+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
+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
+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
+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 [in wanrouter.h pre 3.9]
+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
+EEPROM_MAGIC_VALUE 0x5ab478d2 lanai_dev drivers/atm/lanai.c
+HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.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
+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
+ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
+CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
+DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.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中找到他们。
--- /dev/null
+Chinese translated version of Documentation/process/stable-api-nonsense.rst
+
+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/process/stable-api-nonsense.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: 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>
--- /dev/null
+Chinese translated version of Documentation/process/stable-kernel-rules.rst
+
+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/process/stable-kernel-rules.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+
+中文版维护者: 钟宇 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/process/submitting-patches.rst里的规则。
+
+向稳定版代码树提交补丁的过程:
+
+ - 在确认了补丁符合以上的规则后,将补丁发送到stable@vger.kernel.org。
+ - 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
+ 到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
+ - 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
+ - 安全方面的补丁不要发到这个列表,应该发送到security@kernel.org。
+
+审查周期:
+
+ - 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
+ 及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
+ 到linux-kernel邮件列表。
+ - 审查委员会有48小时的时间,用来决定给该补丁回复ACK还是NAK。
+ - 如果委员会中有成员拒绝这个补丁,或者linux-kernel列表上有人反对这个
+ 补丁,并提出维护者和审查委员会之前没有意识到的问题,补丁会从队列中
+ 丢弃。
+ - 在审查周期结束的时候,那些得到ACK回应的补丁将会被加入到最新的稳定版
+ 发布中,一个新的稳定版发布就此产生。
+ - 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中,而不是通过
+ 通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
+
+审查委员会:
+ - 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。
--- /dev/null
+Chinese translated version of Documentation/process/volatile-considered-harmful.rst
+
+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/process/volatile-considered-harmful.rst 的中文翻译
+
+如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
+交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
+译存在问题,请联系中文版维护者。
+
+英文版维护者: 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 Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
+H. Peter Anvin,Philipp Hahn和Stefan Richter的意见改善了本档。
+++ /dev/null
-Chinese translated version of Documentation/process/stable-api-nonsense.rst
-
-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/process/stable-api-nonsense.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-英文版维护者: 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>
+++ /dev/null
-Chinese translated version of Documentation/process/stable-kernel-rules.rst
-
-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/process/stable-kernel-rules.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-
-中文版维护者: 钟宇 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/process/submitting-patches.rst里的规则。
-
-向稳定版代码树提交补丁的过程:
-
- - 在确认了补丁符合以上的规则后,将补丁发送到stable@vger.kernel.org。
- - 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
- 到的是NAK回复。回复需要几天的时间,这取决于开发者的时间安排。
- - 被接受的补丁会被加到稳定版本队列里,等待其他开发者的审查。
- - 安全方面的补丁不要发到这个列表,应该发送到security@kernel.org。
-
-审查周期:
-
- - 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
- 及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
- 到linux-kernel邮件列表。
- - 审查委员会有48小时的时间,用来决定给该补丁回复ACK还是NAK。
- - 如果委员会中有成员拒绝这个补丁,或者linux-kernel列表上有人反对这个
- 补丁,并提出维护者和审查委员会之前没有意识到的问题,补丁会从队列中
- 丢弃。
- - 在审查周期结束的时候,那些得到ACK回应的补丁将会被加入到最新的稳定版
- 发布中,一个新的稳定版发布就此产生。
- - 安全性补丁将从内核安全小组那里直接接收到稳定版代码树中,而不是通过
- 通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
-
-审查委员会:
- - 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。
+++ /dev/null
-Chinese translated version of Documentation/process/volatile-considered-harmful.rst
-
-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/process/volatile-considered-harmful.rst 的中文翻译
-
-如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
-交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
-译存在问题,请联系中文版维护者。
-
-英文版维护者: 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 Sharma,Johannes Stezenbach,Jesper Juhl,Heikki Orsila,
-H. Peter Anvin,Philipp Hahn和Stefan Richter的意见改善了本档。