Commit 8c79f4cd authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'docs-5.2' of git://git.lwn.net/linux

Pull documentation updates from Jonathan Corbet:
 "A reasonably busy cycle for docs, including:

   - Lots of work on the Chinese and Italian translations

   - Some license-rules clarifications from Christoph

   - Various build-script fixes

   - A new document on memory models

   - RST conversion of the live-patching docs

   - The usual collection of typo fixes and corrections"

* tag 'docs-5.2' of git://git.lwn.net/linux: (140 commits)
  docs/livepatch: Unify style of livepatch documentation in the ReST format
  docs: livepatch: convert docs to ReST and rename to *.rst
  scripts/documentation-file-ref-check: detect broken :doc:`foo`
  scripts/documentation-file-ref-check: don't parse Next/ dir
  LICENSES: Rename other to deprecated
  LICENSES: Clearly mark dual license only licenses
  docs: Don't reference the ZLib license in license-rules.rst
  docs/vm: Minor editorial changes in the THP and hugetlbfs
  docs/vm: add documentation of memory models
  doc:it_IT: translation alignment
  doc: fix typo in PGP guide
  dontdiff: update with Kconfig build artifacts
  docs/zh_CN: fix typos in 1.Intro.rst file
  docs/zh_CN: redirect CoC docs to Chinese version
  doc: mm: migration doesn't use FOLL_SPLIT anymore
  docs: doc-guide: remove the extension from .rst files
  doc: kselftest: Fix KBUILD_OUTPUT usage instructions
  docs: trace: fix some Sphinx warnings
  docs: speculation.txt: mark example blocks as such
  docs: ntb.txt: add blank lines to clean up some Sphinx warnings
  ...
parents 2646719a d9defe44
......@@ -16,6 +16,8 @@ Alan Cox <alan@lxorguk.ukuu.org.uk>
Alan Cox <root@hraefn.swansea.linux.org.uk>
Aleksey Gorelov <aleksey_gorelov@phoenix.com>
Aleksandar Markovic <aleksandar.markovic@mips.com> <aleksandar.markovic@imgtec.com>
Alex Shi <alex.shi@linux.alibaba.com> <alex.shi@intel.com>
Alex Shi <alex.shi@linux.alibaba.com> <alex.shi@linaro.org>
Alexei Starovoitov <ast@kernel.org> <ast@plumgrid.com>
Alexei Starovoitov <ast@kernel.org> <alexei.starovoitov@gmail.com>
Alexei Starovoitov <ast@kernel.org> <ast@fb.com>
......@@ -126,6 +128,8 @@ Leonid I Ananiev <leonid.i.ananiev@intel.com>
Linas Vepstas <linas@austin.ibm.com>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@web.de>
Linus Lüssing <linus.luessing@c0d3.blue> <linus.luessing@ascom.ch>
Li Yang <leoyang.li@nxp.com> <leo@zh-kernel.org>
Li Yang <leoyang.li@nxp.com> <leoli@freescale.com>
Maciej W. Rozycki <macro@mips.com> <macro@imgtec.com>
Marcin Nowakowski <marcin.nowakowski@mips.com> <marcin.nowakowski@imgtec.com>
Mark Brown <broonie@sirena.org.uk>
......@@ -217,6 +221,8 @@ Tejun Heo <htejun@gmail.com>
Thomas Graf <tgraf@suug.ch>
Thomas Pedersen <twp@codeaurora.org>
Tony Luck <tony.luck@intel.com>
TripleX Chung <xxx.phy@gmail.com> <zhongyu@18mail.cn>
TripleX Chung <xxx.phy@gmail.com> <triplex@zh-kernel.org>
Tsuneo Yoshioka <Tsuneo.Yoshioka@f-secure.com>
Uwe Kleine-König <ukleinek@informatik.uni-freiburg.de>
Uwe Kleine-König <ukl@pengutronix.de>
......
......@@ -45,7 +45,7 @@ Description:
use this feature without a clearance from a patch
distributor. Removal (rmmod) of patch modules is permanently
disabled when the feature is used. See
Documentation/livepatch/livepatch.txt for more information.
Documentation/livepatch/livepatch.rst for more information.
What: /sys/kernel/livepatch/<patch>/<object>
Date: Nov 2014
......
......@@ -147,7 +147,7 @@ networking subsystems make sure that the buffers they use are valid
for you to DMA from/to.
DMA addressing capabilities
==========================
===========================
By default, the kernel assumes that your device can address 32-bits of DMA
addressing. For a 64-bit capable device, this needs to be increased, and for
......
......@@ -28,8 +28,13 @@ ifeq ($(HAVE_SPHINX),0)
else # HAVE_SPHINX
# User-friendly check for pdflatex
# User-friendly check for pdflatex and latexmk
HAVE_PDFLATEX := $(shell if which $(PDFLATEX) >/dev/null 2>&1; then echo 1; else echo 0; fi)
HAVE_LATEXMK := $(shell if which latexmk >/dev/null 2>&1; then echo 1; else echo 0; fi)
ifeq ($(HAVE_LATEXMK),1)
PDFLATEX := latexmk -$(PDFLATEX)
endif #HAVE_LATEXMK
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
......@@ -82,7 +87,7 @@ pdfdocs:
else # HAVE_PDFLATEX
pdfdocs: latexdocs
$(foreach var,$(SPHINXDIRS), $(MAKE) PDFLATEX=$(PDFLATEX) LATEXOPTS="$(LATEXOPTS)" -C $(BUILDDIR)/$(var)/latex || exit;)
$(foreach var,$(SPHINXDIRS), $(MAKE) PDFLATEX="$(PDFLATEX)" LATEXOPTS="$(LATEXOPTS)" -C $(BUILDDIR)/$(var)/latex || exit;)
endif # HAVE_PDFLATEX
......
On atomic bitops.
=============
Atomic bitops
=============
While our bitmap_{}() functions are non-atomic, we have a number of operations
operating on single bits in a bitmap that are atomic.
......
Clearing WARN_ONCE
------------------
WARN_ONCE / WARN_ON_ONCE / printk_once only emit a message once.
......
......@@ -22,7 +22,6 @@ Core utilities
workqueue
genericirq
xarray
flexible-arrays
librs
genalloc
errseq
......
......@@ -7,6 +7,11 @@ directory. These are intended to be small tests to exercise individual code
paths in the kernel. Tests are intended to be run after building, installing
and booting a kernel.
You can find additional information on Kselftest framework, how to
write new tests using the framework on Kselftest wiki:
https://kselftest.wiki.kernel.org/
On some systems, hot-plug tests could hang forever waiting for cpu and
memory to be ready to be offlined. A special hot-plug target is created
to run the full range of hot-plug tests. In default mode, hot-plug tests run
......@@ -35,17 +40,32 @@ To build and run the tests with a single command, use::
Note that some tests will require root privileges.
Build and run from user specific object directory (make O=dir)::
Kselftest supports saving output files in a separate directory and then
running tests. To locate output files in a separate directory two syntaxes
are supported. In both cases the working directory must be the root of the
kernel src. This is applicable to "Running a subset of selftests" section
below.
To build, save output files in a separate directory with O= ::
$ make O=/tmp/kselftest kselftest
Build and run KBUILD_OUTPUT directory (make KBUILD_OUTPUT=)::
To build, save output files in a separate directory with KBUILD_OUTPUT ::
$ export KBUILD_OUTPUT=/tmp/kselftest; make kselftest
$ make KBUILD_OUTPUT=/tmp/kselftest kselftest
The O= assignment takes precedence over the KBUILD_OUTPUT environment
variable.
The above commands run the tests and print pass/fail summary to make it
easier to understand the test results. Please find the detailed individual
test results for each test in /tmp/testname file(s).
The above commands by default run the tests and print full pass/fail report.
Kselftest supports "summary" option to make it easier to understand the test
results. Please find the detailed individual test results for each test in
/tmp/testname file(s) when summary option is specified. This is applicable
to "Running a subset of selftests" section below.
To run kselftest with summary option enabled ::
$ make summary=1 kselftest
Running a subset of selftests
=============================
......@@ -61,17 +81,13 @@ You can specify multiple tests to build and run::
$ make TARGETS="size timers" kselftest
Build and run from user specific object directory (make O=dir)::
To build, save output files in a separate directory with O= ::
$ make O=/tmp/kselftest TARGETS="size timers" kselftest
Build and run KBUILD_OUTPUT directory (make KBUILD_OUTPUT=)::
$ make KBUILD_OUTPUT=/tmp/kselftest TARGETS="size timers" kselftest
To build, save output files in a separate directory with KBUILD_OUTPUT ::
The above commands run the tests and print pass/fail summary to make it
easier to understand the test results. Please find the detailed individual
test results for each test in /tmp/testname file(s).
$ export KBUILD_OUTPUT=/tmp/kselftest; make TARGETS="size timers" kselftest
See the top-level tools/testing/selftests/Makefile for the list of all
possible targets.
......
......@@ -7,9 +7,9 @@ How to write kernel documentation
.. toctree::
:maxdepth: 1
sphinx.rst
kernel-doc.rst
parse-headers.rst
sphinx
kernel-doc
parse-headers
.. only:: subproject and html
......
......@@ -127,7 +127,7 @@ flask.h
fore200e_mkfirm
fore200e_pca_fw.c*
gconf
gconf.glade.h
gconf-cfg
gen-devlist
gen_crc32table
gen_init_cpio
......@@ -148,24 +148,22 @@ int32.c
int4.c
int8.c
kallsyms
kconfig
keywords.c
ksym.c*
ksym.h*
kxgettext
*lex.c
*lex.*.c
linux
logo_*.c
logo_*_clut224.c
logo_*_mono.c
lxdialog
mach-types
mach-types.h
machtypes.h
map
map_hugetlb
mconf
mconf-cfg
miboot*
mk_elfconfig
mkboot
......@@ -183,6 +181,7 @@ modules.builtin.modinfo
modules.order
modversions.h*
nconf
nconf-cfg
ncscope.*
offset.h
oui.c*
......@@ -202,6 +201,7 @@ pnmtologo
ppc_defs.h*
pss_boot.h
qconf
qconf-cfg
r100_reg_safe.h
r200_reg_safe.h
r300_reg_safe.h
......
......@@ -201,7 +201,7 @@ Bus implements below API for allocate a stream which needs to be called once
per stream. From ASoC DPCM framework, this stream state maybe linked to
.startup() operation.
.. code-block:: c
.. code-block:: c
int sdw_alloc_stream(char * stream_name);
......@@ -228,7 +228,7 @@ the respective Master(s) and Slave(s) associated with stream. These APIs can
only be invoked once by respective Master(s) and Slave(s). From ASoC DPCM
framework, this stream state is linked to .hw_params() operation.
.. code-block:: c
.. code-block:: c
int sdw_stream_add_master(struct sdw_bus * bus,
struct sdw_stream_config * stream_config,
......@@ -274,7 +274,7 @@ Bus implements below API for PREPARE state which needs to be called once per
stream. From ASoC DPCM framework, this stream state is linked to
.prepare() operation.
.. code-block:: c
.. code-block:: c
int sdw_prepare_stream(struct sdw_stream_runtime * stream);
......@@ -304,7 +304,7 @@ Bus implements below API for ENABLE state which needs to be called once per
stream. From ASoC DPCM framework, this stream state is linked to
.trigger() start operation.
.. code-block:: c
.. code-block:: c
int sdw_enable_stream(struct sdw_stream_runtime * stream);
......@@ -332,7 +332,7 @@ Bus implements below API for DISABLED state which needs to be called once
per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.
.. code-block:: c
.. code-block:: c
int sdw_disable_stream(struct sdw_stream_runtime * stream);
......@@ -357,7 +357,7 @@ Bus implements below API for DEPREPARED state which needs to be called once
per stream. From ASoC DPCM framework, this stream state is linked to
.trigger() stop operation.
.. code-block:: c
.. code-block:: c
int sdw_deprepare_stream(struct sdw_stream_runtime * stream);
......@@ -382,7 +382,7 @@ Bus implements below APIs for RELEASE state which needs to be called by
all the Master(s) and Slave(s) associated with stream. From ASoC DPCM
framework, this stream state is linked to .hw_free() operation.
.. code-block:: c
.. code-block:: c
int sdw_stream_remove_master(struct sdw_bus * bus,
struct sdw_stream_runtime * stream);
......@@ -395,7 +395,7 @@ stream assigned as part of ALLOCATED state.
In .shutdown() the data structure maintaining stream state are freed up.
.. code-block:: c
.. code-block:: c
void sdw_release_stream(struct sdw_stream_runtime * stream);
......
......@@ -4,7 +4,7 @@
Livepatch (un)patch-callbacks provide a mechanism for livepatch modules
to execute callback functions when a kernel object is (un)patched. They
can be considered a "power feature" that extends livepatching abilities
can be considered a **power feature** that **extends livepatching abilities**
to include:
- Safe updates to global data
......@@ -17,6 +17,9 @@ In most cases, (un)patch callbacks will need to be used in conjunction
with memory barriers and kernel synchronization primitives, like
mutexes/spinlocks, or even stop_machine(), to avoid concurrency issues.
1. Motivation
=============
Callbacks differ from existing kernel facilities:
- Module init/exit code doesn't run when disabling and re-enabling a
......@@ -28,21 +31,31 @@ Callbacks are part of the klp_object structure and their implementation
is specific to that klp_object. Other livepatch objects may or may not
be patched, irrespective of the target klp_object's current state.
2. Callback types
=================
Callbacks can be registered for the following livepatch actions:
* Pre-patch - before a klp_object is patched
* Pre-patch
- before a klp_object is patched
* Post-patch - after a klp_object has been patched and is active
* Post-patch
- after a klp_object has been patched and is active
across all tasks
* Pre-unpatch - before a klp_object is unpatched (ie, patched code is
* Pre-unpatch
- before a klp_object is unpatched (ie, patched code is
active), used to clean up post-patch callback
resources
* Post-unpatch - after a klp_object has been patched, all code has
* Post-unpatch
- after a klp_object has been patched, all code has
been restored and no tasks are running patched code,
used to cleanup pre-patch callback resources
3. How it works
===============
Each callback is optional, omitting one does not preclude specifying any
other. However, the livepatching core executes the handlers in
symmetry: pre-patch callbacks have a post-unpatch counterpart and
......@@ -86,11 +99,14 @@ If the object did successfully patch, but the patch transition never
started for some reason (e.g., if another object failed to patch),
only the post-unpatch callback will be called.
4. Use cases
============
Example Use-cases
=================
Sample livepatch modules demonstrating the callback API can be found in
samples/livepatch/ directory. These samples were modified for use in
kselftests and can be found in the lib/livepatch directory.
Update global data
Global data update
------------------
A pre-patch callback can be useful to update a global variable. For
......@@ -103,24 +119,15 @@ patch the data *after* patching is complete with a post-patch callback,
so that tcp_send_challenge_ack() could first be changed to read
sysctl_tcp_challenge_ack_limit with READ_ONCE.
Support __init and probe function patches
__init and probe function patches support
-----------------------------------------
Although __init and probe functions are not directly livepatch-able, it
may be possible to implement similar updates via pre/post-patch
callbacks.
48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST") change the way that
The commit ``48900cb6af42 ("virtio-net: drop NETIF_F_FRAGLIST")`` change the way that
virtnet_probe() initialized its driver's net_device features. A
pre/post-patch callback could iterate over all such devices, making a
similar change to their hw_features value. (Client functions of the
value may need to be updated accordingly.)
Other Examples
==============
Sample livepatch modules demonstrating the callback API can be found in
samples/livepatch/ directory. These samples were modified for use in
kselftests and can be found in the lib/livepatch directory.
......@@ -18,7 +18,7 @@ Usage
-----
The atomic replace can be enabled by setting "replace" flag in struct klp_patch,
for example:
for example::
static struct klp_patch patch = {
.mod = THIS_MODULE,
......@@ -49,19 +49,19 @@ Features
The atomic replace allows:
+ Atomically revert some functions in a previous patch while
- Atomically revert some functions in a previous patch while
upgrading other functions.
+ Remove eventual performance impact caused by core redirection
- Remove eventual performance impact caused by core redirection
for functions that are no longer patched.
+ Decrease user confusion about dependencies between livepatches.
- Decrease user confusion about dependencies between livepatches.
Limitations:
------------
+ Once the operation finishes, there is no straightforward way
- Once the operation finishes, there is no straightforward way
to reverse it and restore the replaced patches atomically.
A good practice is to set .replace flag in any released livepatch.
......@@ -74,7 +74,7 @@ Limitations:
only when the transition was not forced.
+ Only the (un)patching callbacks from the _new_ cumulative livepatch are
- Only the (un)patching callbacks from the _new_ cumulative livepatch are
executed. Any callbacks from the replaced patches are ignored.
In other words, the cumulative patch is responsible for doing any actions
......@@ -93,7 +93,7 @@ Limitations:
enabled patches were called.
+ There is no special handling of shadow variables. Livepatch authors
- There is no special handling of shadow variables. Livepatch authors
must create their own rules how to pass them from one cumulative
patch to the other. Especially that they should not blindly remove
them in module_exit() functions.
......
:orphan:
===================
Kernel Livepatching
===================
.. toctree::
:maxdepth: 1
livepatch
callbacks
cumulative-patches
module-elf-format
shadow-vars
.. only:: subproject and html
Indices
=======
* :ref:`genindex`
......@@ -4,22 +4,22 @@ Livepatch
This document outlines basic information about kernel livepatching.
Table of Contents:
1. Motivation
2. Kprobes, Ftrace, Livepatching
3. Consistency model
4. Livepatch module
4.1. New functions
4.2. Metadata
5. Livepatch life-cycle
5.1. Loading
5.2. Enabling
5.3. Replacing
5.4. Disabling
5.5. Removing
6. Sysfs
7. Limitations
.. Table of Contents:
1. Motivation
2. Kprobes, Ftrace, Livepatching
3. Consistency model
4. Livepatch module
4.1. New functions
4.2. Metadata
5. Livepatch life-cycle
5.1. Loading
5.2. Enabling
5.3. Replacing
5.4. Disabling
5.5. Removing
6. Sysfs
7. Limitations
1. Motivation
......@@ -40,14 +40,14 @@ There are multiple mechanisms in the Linux kernel that are directly related
to redirection of code execution; namely: kernel probes, function tracing,
and livepatching:
+ The kernel probes are the most generic. The code can be redirected by
- The kernel probes are the most generic. The code can be redirected by
putting a breakpoint instruction instead of any instruction.
+ The function tracer calls the code from a predefined location that is
- The function tracer calls the code from a predefined location that is
close to the function entry point. This location is generated by the
compiler using the '-pg' gcc option.
+ Livepatching typically needs to redirect the code at the very beginning
- Livepatching typically needs to redirect the code at the very beginning
of the function entry before the function parameters or the stack
are in any way modified.
......@@ -249,7 +249,7 @@ The patch contains only functions that are really modified. But they
might want to access functions or data from the original source file
that may only be locally accessible. This can be solved by a special
relocation section in the generated livepatch module, see
Documentation/livepatch/module-elf-format.txt for more details.
Documentation/livepatch/module-elf-format.rst for more details.
4.2. Metadata
......@@ -258,7 +258,7 @@ Documentation/livepatch/module-elf-format.txt for more details.
The patch is described by several structures that split the information
into three levels:
+ struct klp_func is defined for each patched function. It describes
- struct klp_func is defined for each patched function. It describes
the relation between the original and the new implementation of a
particular function.
......@@ -275,7 +275,7 @@ into three levels:
only for a particular object ( vmlinux or a kernel module ). Note that
kallsyms allows for searching symbols according to the object name.
+ struct klp_object defines an array of patched functions (struct
- struct klp_object defines an array of patched functions (struct
klp_func) in the same object. Where the object is either vmlinux
(NULL) or a module name.
......@@ -285,7 +285,7 @@ into three levels:
only when they are available.
+ struct klp_patch defines an array of patched objects (struct
- struct klp_patch defines an array of patched objects (struct
klp_object).
This structure handles all patched functions consistently and eventually,
......@@ -337,14 +337,16 @@ operation fails.
Second, livepatch enters into a transition state where tasks are converging
to the patched state. If an original function is patched for the first
time, a function specific struct klp_ops is created and an universal
ftrace handler is registered[*]. This stage is indicated by a value of '1'
ftrace handler is registered\ [#]_. This stage is indicated by a value of '1'
in /sys/kernel/livepatch/<name>/transition. For more information about
this process, see the "Consistency model" section.
Finally, once all tasks have been patched, the 'transition' value changes
to '0'.
[*] Note that functions might be patched multiple times. The ftrace handler
.. [#]
Note that functions might be patched multiple times. The ftrace handler
is registered only once for a given function. Further patches just add
an entry to the list (see field `func_stack`) of the struct klp_ops.
The right implementation is selected by the ftrace handler, see
......@@ -368,7 +370,7 @@ the ftrace handler is unregistered and the struct klp_ops is
freed when the related function is not modified by the new patch
and func_stack list becomes empty.
See Documentation/livepatch/cumulative-patches.txt for more details.
See Documentation/livepatch/cumulative-patches.rst for more details.
5.4. Disabling
......@@ -421,7 +423,7 @@ See Documentation/ABI/testing/sysfs-kernel-livepatch for more details.
The current Livepatch implementation has several limitations:
+ Only functions that can be traced could be patched.
- Only functions that can be traced could be patched.
Livepatch is based on the dynamic ftrace. In particular, functions
implementing ftrace or the livepatch ftrace handler could not be
......@@ -431,7 +433,7 @@ The current Livepatch implementation has several limitations:
+ Livepatch works reliably only when the dynamic ftrace is located at
- Livepatch works reliably only when the dynamic ftrace is located at
the very beginning of the function.
The function need to be redirected before the stack or the function
......@@ -445,7 +447,7 @@ The current Livepatch implementation has several limitations:
this is handled on the ftrace level.
+ Kretprobes using the ftrace framework conflict with the patched
- Kretprobes using the ftrace framework conflict with the patched
functions.
Both kretprobes and livepatches use a ftrace handler that modifies
......@@ -453,7 +455,7 @@ The current Livepatch implementation has several limitations:
is rejected when the handler is already in use by the other.
+ Kprobes in the original function are ignored when the code is
- Kprobes in the original function are ignored when the code is
redirected to the new implementation.
There is a work in progress to add warnings about this situation.
......@@ -4,33 +4,21 @@ Livepatch module Elf format
This document outlines the Elf format requirements that livepatch modules must follow.
-----------------
Table of Contents
-----------------
0. Background and motivation
1. Livepatch modinfo field
2. Livepatch relocation sections
2.1 What are livepatch relocation sections?
2.2 Livepatch relocation section format
2.2.1 Required flags
2.2.2 Required name format
2.2.3 Example livepatch relocation section names
2.2.4 Example `readelf --sections` output
2.2.5 Example `readelf --relocs` output
3. Livepatch symbols
3.1 What are livepatch symbols?
3.2 A livepatch module's symbol table
3.3 Livepatch symbol format
3.3.1 Required flags
3.3.2 Required name format
3.3.3 Example livepatch symbol names
3.3.4 Example `readelf --symbols` output
4. Architecture-specific sections
5. Symbol table and Elf section access
----------------------------
0. Background and motivation
----------------------------
.. Table of Contents
1. Background and motivation
2. Livepatch modinfo field
3. Livepatch relocation sections
3.1 Livepatch relocation section format
4. Livepatch symbols
4.1 A livepatch module's symbol table
4.2 Livepatch symbol format
5. Architecture-specific sections
6. Symbol table and Elf section access
1. Background and motivation
============================
Formerly, livepatch required separate architecture-specific code to write
relocations. However, arch-specific code to write relocations already
......@@ -52,8 +40,8 @@ relocation sections and symbols, which are described in this document. The
Elf constants used to mark livepatch symbols and relocation sections were
selected from OS-specific ranges according to the definitions from glibc.
0.1 Why does livepatch need to write its own relocations?
---------------------------------------------------------
Why does livepatch need to write its own relocations?
-----------------------------------------------------
A typical livepatch module contains patched versions of functions that can
reference non-exported global symbols and non-included local symbols.
Relocations referencing these types of symbols cannot be left in as-is
......@@ -72,13 +60,8 @@ relas reference are special livepatch symbols (see section 2 and 3). The
arch-specific livepatch relocation code is replaced by a call to
apply_relocate_add().
================================
PATCH MODULE FORMAT REQUIREMENTS
================================
--------------------------
1. Livepatch modinfo field
--------------------------
2. Livepatch modinfo field
==========================
Livepatch modules are required to have the "livepatch" modinfo attribute.
See the sample livepatch module in samples/livepatch/ for how this is done.
......@@ -87,22 +70,23 @@ Livepatch modules can be identified by users by using the 'modinfo' command
and looking for the presence of the "livepatch" field. This field is also
used by the kernel module loader to identify livepatch modules.
Example modinfo output:
-----------------------
% modinfo livepatch-meminfo.ko
filename: livepatch-meminfo.ko
livepatch: Y
license: GPL
depends:
vermagic: 4.3.0+ SMP mod_unload
--------------------------------
2. Livepatch relocation sections
--------------------------------
-------------------------------------------
2.1 What are livepatch relocation sections?
-------------------------------------------
Example:
--------
**Modinfo output:**
::
% modinfo livepatch-meminfo.ko
filename: livepatch-meminfo.ko
livepatch: Y
license: GPL
depends:
vermagic: 4.3.0+ SMP mod_unload
3. Livepatch relocation sections
================================
A livepatch module manages its own Elf relocation sections to apply
relocations to modules as well as to the kernel (vmlinux) at the
appropriate time. For example, if a patch module patches a driver that is
......@@ -127,12 +111,9 @@ Every symbol referenced by a rela in a livepatch relocation section is a
livepatch symbol. These must be resolved before livepatch can call
apply_relocate_add(). See Section 3 for more information.
---------------------------------------
2.2 Livepatch relocation section format
---------------------------------------
3.1 Livepatch relocation section format
=======================================
2.2.1 Required flags
--------------------
Livepatch relocation sections must be marked with the SHF_RELA_LIVEPATCH
section flag. See include/uapi/linux/elf.h for the definition. The module
loader recognizes this flag and will avoid applying those relocation sections
......@@ -140,28 +121,39 @@ at patch module load time. These sections must also be marked with SHF_ALLOC,
so that the module loader doesn't discard them on module load (i.e. they will
be copied into memory along with the other SHF_ALLOC sections).
2.2.2 Required name format
--------------------------
The name of a livepatch relocation section must conform to the following format:
The name of a livepatch relocation section must conform to the following
format::
.klp.rela.objname.section_name
^ ^^ ^ ^ ^
|________||_____| |__________|
[A] [B] [C]
.klp.rela.objname.section_name
^ ^^ ^ ^ ^
|________||_____| |__________|
[A] [B] [C]
[A] The relocation section name is prefixed with the string ".klp.rela."
[B] The name of the object (i.e. "vmlinux" or name of module) to
which the relocation section belongs follows immediately after the prefix.
[C] The actual name of the section to which this relocation section applies.
[A]
The relocation section name is prefixed with the string ".klp.rela."
2.2.3 Example livepatch relocation section names:
-------------------------------------------------
.klp.rela.ext4.text.ext4_attr_store
.klp.rela.vmlinux.text.cmdline_proc_show
[B]
The name of the object (i.e. "vmlinux" or name of module) to
which the relocation section belongs follows immediately after the prefix.
[C]
The actual name of the section to which this relocation section applies.
Examples:
---------
**Livepatch relocation section names:**
::
.klp.rela.ext4.text.ext4_attr_store
.klp.rela.vmlinux.text.cmdline_proc_show
**`readelf --sections` output for a patch
module that patches vmlinux and modules 9p, btrfs, ext4:**
::
2.2.4 Example `readelf --sections` output for a patch
module that patches vmlinux and modules 9p, btrfs, ext4:
--------------------------------------------------------
Section Headers:
[Nr] Name Type Address Off Size ES Flg Lk Inf Al
[ snip ]
......@@ -175,31 +167,33 @@ module that patches vmlinux and modules 9p, btrfs, ext4:
[ snip ] ^ ^
| |
[*] [*]
[*] Livepatch relocation sections are SHT_RELA sections but with a few special
characteristics. Notice that they are marked SHF_ALLOC ("A") so that they will
not be discarded when the module is loaded into memory, as well as with the
SHF_RELA_LIVEPATCH flag ("o" - for OS-specific).
2.2.5 Example `readelf --relocs` output for a patch module:
-----------------------------------------------------------
Relocation section '.klp.rela.btrfs.text.btrfs_feature_attr_show' at offset 0x2ba0 contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
000000000000001f 0000005e00000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.printk,0 - 4
0000000000000028 0000003d0000000b R_X86_64_32S 0000000000000000 .klp.sym.btrfs.btrfs_ktype,0 + 0
0000000000000036 0000003b00000002 R_X86_64_PC32 0000000000000000 .klp.sym.btrfs.can_modify_feature.isra.3,0 - 4
000000000000004c 0000004900000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.snprintf,0 - 4
[ snip ] ^
|
[*]
[*] Every symbol referenced by a relocation is a livepatch symbol.
--------------------
3. Livepatch symbols
--------------------
-------------------------------
3.1 What are livepatch symbols?
-------------------------------
[*]
Livepatch relocation sections are SHT_RELA sections but with a few special
characteristics. Notice that they are marked SHF_ALLOC ("A") so that they will
not be discarded when the module is loaded into memory, as well as with the
SHF_RELA_LIVEPATCH flag ("o" - for OS-specific).
**`readelf --relocs` output for a patch module:**
::
Relocation section '.klp.rela.btrfs.text.btrfs_feature_attr_show' at offset 0x2ba0 contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
000000000000001f 0000005e00000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.printk,0 - 4
0000000000000028 0000003d0000000b R_X86_64_32S 0000000000000000 .klp.sym.btrfs.btrfs_ktype,0 + 0
0000000000000036 0000003b00000002 R_X86_64_PC32 0000000000000000 .klp.sym.btrfs.can_modify_feature.isra.3,0 - 4
000000000000004c 0000004900000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.snprintf,0 - 4
[ snip ] ^
|
[*]
[*]
Every symbol referenced by a relocation is a livepatch symbol.
4. Livepatch symbols
====================
Livepatch symbols are symbols referred to by livepatch relocation sections.
These are symbols accessed from new versions of functions for patched
objects, whose addresses cannot be resolved by the module loader (because
......@@ -219,9 +213,8 @@ loader can identify and ignore them. Livepatch modules keep these symbols
in their symbol tables, and the symbol table is made accessible through
module->symtab.
-------------------------------------
3.2 A livepatch module's symbol table
-------------------------------------
4.1 A livepatch module's symbol table
=====================================
Normally, a stripped down copy of a module's symbol table (containing only
"core" symbols) is made available through module->symtab (See layout_symtab()
in kernel/module.c). For livepatch modules, the symbol table copied into memory
......@@ -231,71 +224,82 @@ relocation section refer to their respective symbols with their symbol indices,
and the original symbol indices (and thus the symtab ordering) must be
preserved in order for apply_relocate_add() to find the right symbol.
For example, take this particular rela from a livepatch module:
Relocation section '.klp.rela.btrfs.text.btrfs_feature_attr_show' at offset 0x2ba0 contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
000000000000001f 0000005e00000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.printk,0 - 4
This rela refers to the symbol '.klp.sym.vmlinux.printk,0', and the symbol index is encoded
in 'Info'. Here its symbol index is 0x5e, which is 94 in decimal, which refers to the
symbol index 94.
And in this patch module's corresponding symbol table, symbol index 94 refers to that very symbol:
[ snip ]
94: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.printk,0
[ snip ]
---------------------------
3.3 Livepatch symbol format
---------------------------
3.3.1 Required flags
--------------------
For example, take this particular rela from a livepatch module:::
Relocation section '.klp.rela.btrfs.text.btrfs_feature_attr_show' at offset 0x2ba0 contains 4 entries:
Offset Info Type Symbol's Value Symbol's Name + Addend
000000000000001f 0000005e00000002 R_X86_64_PC32 0000000000000000 .klp.sym.vmlinux.printk,0 - 4
This rela refers to the symbol '.klp.sym.vmlinux.printk,0', and the symbol index is encoded
in 'Info'. Here its symbol index is 0x5e, which is 94 in decimal, which refers to the
symbol index 94.
And in this patch module's corresponding symbol table, symbol index 94 refers to that very symbol:
[ snip ]
94: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.printk,0
[ snip ]
4.2 Livepatch symbol format
===========================
Livepatch symbols must have their section index marked as SHN_LIVEPATCH, so
that the module loader can identify them and not attempt to resolve them.
See include/uapi/linux/elf.h for the actual definitions.
3.3.2 Required name format
--------------------------
Livepatch symbol names must conform to the following format:
.klp.sym.objname.symbol_name,sympos
^ ^^ ^ ^ ^ ^
|_______||_____| |_________| |
[A] [B] [C] [D]
[A] The symbol name is prefixed with the string ".klp.sym."
[B] The name of the object (i.e. "vmlinux" or name of module) to
which the symbol belongs follows immediately after the prefix.
[C] The actual name of the symbol.
[D] The position of the symbol in the object (as according to kallsyms)
This is used to differentiate duplicate symbols within the same
object. The symbol position is expressed numerically (0, 1, 2...).
The symbol position of a unique symbol is 0.
3.3.3 Example livepatch symbol names:
-------------------------------------
.klp.sym.vmlinux.snprintf,0
.klp.sym.vmlinux.printk,0
.klp.sym.btrfs.btrfs_ktype,0
3.3.4 Example `readelf --symbols` output for a patch module:
------------------------------------------------------------
Symbol table '.symtab' contains 127 entries:
Num: Value Size Type Bind Vis Ndx Name
[ snip ]
73: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.snprintf,0
74: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.capable,0
75: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.find_next_bit,0
76: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.si_swapinfo,0
[ snip ] ^
|
[*]
[*] Note that the 'Ndx' (Section index) for these symbols is SHN_LIVEPATCH (0xff20).
"OS" means OS-specific.
---------------------------------
4. Architecture-specific sections
---------------------------------
Livepatch symbol names must conform to the following format::
.klp.sym.objname.symbol_name,sympos
^ ^^ ^ ^ ^ ^
|_______||_____| |_________| |
[A] [B] [C] [D]
[A]
The symbol name is prefixed with the string ".klp.sym."
[B]
The name of the object (i.e. "vmlinux" or name of module) to
which the symbol belongs follows immediately after the prefix.
[C]
The actual name of the symbol.
[D]
The position of the symbol in the object (as according to kallsyms)
This is used to differentiate duplicate symbols within the same
object. The symbol position is expressed numerically (0, 1, 2...).
The symbol position of a unique symbol is 0.
Examples:
---------
**Livepatch symbol names:**
::
.klp.sym.vmlinux.snprintf,0
.klp.sym.vmlinux.printk,0
.klp.sym.btrfs.btrfs_ktype,0
**`readelf --symbols` output for a patch module:**
::
Symbol table '.symtab' contains 127 entries:
Num: Value Size Type Bind Vis Ndx Name
[ snip ]
73: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.snprintf,0
74: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.capable,0
75: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.find_next_bit,0
76: 0000000000000000 0 NOTYPE GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.si_swapinfo,0
[ snip ] ^
|
[*]
[*]
Note that the 'Ndx' (Section index) for these symbols is SHN_LIVEPATCH (0xff20).
"OS" means OS-specific.
5. Architecture-specific sections
=================================
Architectures may override arch_klp_init_object_loaded() to perform
additional arch-specific tasks when a target module loads, such as applying
arch-specific sections. On x86 for example, we must apply per-object
......@@ -304,20 +308,19 @@ These sections must be prefixed with ".klp.arch.$objname." so that they can
be easily identified when iterating through a patch module's Elf sections
(See arch/x86/kernel/livepatch.c for a complete example).
--------------------------------------
5. Symbol table and Elf section access
--------------------------------------
6. Symbol table and Elf section access
======================================
A livepatch module's symbol table is accessible through module->symtab.
Since apply_relocate_add() requires access to a module's section headers,
symbol table, and relocation section indices, Elf information is preserved for
livepatch modules and is made accessible by the module loader through
module->klp_info, which is a klp_modinfo struct. When a livepatch module loads,
this struct is filled in by the module loader. Its fields are documented below:
struct klp_modinfo {
Elf_Ehdr hdr; /* Elf header */
Elf_Shdr *sechdrs; /* Section header table */
char *secstrings; /* String table for the section headers */
unsigned int symndx; /* The symbol table section index */
};
this struct is filled in by the module loader. Its fields are documented below::
struct klp_modinfo {
Elf_Ehdr hdr; /* Elf header */
Elf_Shdr *sechdrs; /* Section header table */
char *secstrings; /* String table for the section headers */
unsigned int symndx; /* The symbol table section index */
};
......@@ -27,10 +27,13 @@ A hashtable references all shadow variables. These references are
stored and retrieved through a <obj, id> pair.
* The klp_shadow variable data structure encapsulates both tracking
meta-data and shadow-data:
meta-data and shadow-data:
- meta-data
- obj - pointer to parent object
- id - data identifier
- data[] - storage for shadow data
It is important to note that the klp_shadow_alloc() and
......@@ -47,31 +50,43 @@ to do actions that can be done only once when a new variable is allocated.
* klp_shadow_alloc() - allocate and add a new shadow variable
- search hashtable for <obj, id> pair
- if exists
- WARN and return NULL
- if <obj, id> doesn't already exist
- allocate a new shadow variable
- initialize the variable using a custom constructor and data when provided
- add <obj, id> to the global hashtable
* klp_shadow_get_or_alloc() - get existing or alloc a new shadow variable
- search hashtable for <obj, id> pair
- if exists
- return existing shadow variable
- if <obj, id> doesn't already exist
- allocate a new shadow variable
- initialize the variable using a custom constructor and data when provided
- add <obj, id> pair to the global hashtable
* klp_shadow_free() - detach and free a <obj, id> shadow variable
- find and remove a <obj, id> reference from global hashtable
- if found
- call destructor function if defined
- free shadow variable
* klp_shadow_free_all() - detach and free all <*, id> shadow variables
- find and remove any <*, id> references from global hashtable
- if found
- call destructor function if defined
- free shadow variable
......@@ -102,12 +117,12 @@ parent "goes live" (ie, any shadow variable get-API requests are made
for this <obj, id> pair.)
For commit 1d147bfa6429, when a parent sta_info structure is allocated,
allocate a shadow copy of the ps_lock pointer, then initialize it:
allocate a shadow copy of the ps_lock pointer, then initialize it::
#define PS_LOCK 1
struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
const u8 *addr, gfp_t gfp)
{
#define PS_LOCK 1
struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
const u8 *addr, gfp_t gfp)
{
struct sta_info *sta;
spinlock_t *ps_lock;
......@@ -123,10 +138,10 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
...
When requiring a ps_lock, query the shadow variable API to retrieve one
for a specific struct sta_info:
for a specific struct sta_info:::
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
spinlock_t *ps_lock;
/* sync with ieee80211_tx_h_unicast_ps_buf */
......@@ -136,10 +151,10 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
...
When the parent sta_info structure is freed, first free the shadow
variable:
variable::
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
void sta_info_free(struct ieee80211_local *local, struct sta_info *sta)
{
klp_shadow_free(sta, PS_LOCK, NULL);
kfree(sta);
...
......@@ -155,19 +170,19 @@ these cases, the klp_shadow_get_or_alloc() call can be used to attach
shadow variables to parents already in-flight.
For commit 1d147bfa6429, a good spot to allocate a shadow spinlock is
inside ieee80211_sta_ps_deliver_wakeup():
inside ieee80211_sta_ps_deliver_wakeup()::
int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
{
int ps_lock_shadow_ctor(void *obj, void *shadow_data, void *ctor_data)
{
spinlock_t *lock = shadow_data;
spin_lock_init(lock);
return 0;
}
}
#define PS_LOCK 1
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
#define PS_LOCK 1
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
spinlock_t *ps_lock;
/* sync with ieee80211_tx_h_unicast_ps_buf */
......@@ -200,10 +215,12 @@ suggests how to handle the parent object.
=============
* https://github.com/dynup/kpatch
The livepatch implementation is based on the kpatch version of shadow
variables.
The livepatch implementation is based on the kpatch version of shadow
variables.
* http://files.mkgnu.net/files/dynamos/doc/papers/dynamos_eurosys_07.pdf
Dynamic and Adaptive Updates of Non-Quiescent Subsystems in Commodity
Operating System Kernels (Kritis Makris, Kyung Dong Ryu 2007) presented
a datatype update technique called "shadow data structures".
Dynamic and Adaptive Updates of Non-Quiescent Subsystems in Commodity
Operating System Kernels (Kritis Makris, Kyung Dong Ryu 2007) presented
a datatype update technique called "shadow data structures".
......@@ -41,9 +41,10 @@ mainly used to perform the proper memory window initialization. Typically
there are two types of memory window interfaces supported by the NTB API:
inbound translation configured on the local ntb port and outbound translation
configured by the peer, on the peer ntb port. The first type is
depicted on the next figure
depicted on the next figure::
Inbound translation:
Inbound translation:
Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
____________
| dma-mapped |-ntb_mw_set_trans(addr) |
......@@ -58,9 +59,10 @@ maps corresponding outbound memory window so to have access to the shared
memory region.
The second type of interface, that implies the shared windows being
initialized by a peer device, is depicted on the figure:
initialized by a peer device, is depicted on the figure::
Outbound translation:
Outbound translation:
Memory: Local NTB Port: Peer NTB Port: Peer MMIO:
____________ ______________
| dma-mapped | | | MW base addr |<== memory-mapped IO
......@@ -75,11 +77,13 @@ outbound memory window so to have access to the shared memory region.
As one can see the described scenarios can be combined in one portable
algorithm.
Local device:
1) Allocate memory for a shared window
2) Initialize memory window by translated address of the allocated region
(it may fail if local memory window initialization is unsupported)
3) Send the translated address and memory window index to a peer device
Peer device:
1) Initialize memory window with retrieved address of the allocated
by another device memory region (it may fail if peer memory window
......@@ -88,6 +92,7 @@ algorithm.
In accordance with this scenario, the NTB Memory Window API can be used as
follows:
Local device:
1) ntb_mw_count(pidx) - retrieve number of memory ranges, which can
be allocated for memory windows between local device and peer device
......@@ -103,6 +108,7 @@ follows:
5) Send translated base address (usually together with memory window
number) to the peer device using, for instance, scratchpad or message
registers.
Peer device:
1) ntb_peer_mw_set_trans(pidx, midx) - try to set received from other
device (related to pidx) translated address for specified memory
......
......@@ -216,10 +216,12 @@ The tags in common use are:
which can be found in :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
Code without a proper signoff cannot be merged into the mainline.
- Co-developed-by: states that the patch was also created by another developer
along with the original author. This is useful at times when multiple
people work on a single patch. Note, this person also needs to have a
Signed-off-by: line in the patch as well.
- Co-developed-by: states that the patch was co-created by several developers;
it is a used to give attribution to co-authors (in addition to the author
attributed by the From: tag) when multiple people work on a single patch.
Every Co-developed-by: must be immediately followed by a Signed-off-by: of
the associated co-author. Details and examples can be found in
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>`.
- Acked-by: indicates an agreement by another developer (often a
maintainer of the relevant code) that the patch is appropriate for
......
......@@ -843,7 +843,8 @@ used.
The kernel provides the following general purpose memory allocators:
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), and
vzalloc(). Please refer to the API documentation for further information
about them.
about them. :ref:`Documentation/core-api/memory-allocation.rst
<memory_allocation>`
The preferred form for passing a size of a struct is the following:
......@@ -874,6 +875,9 @@ The preferred form for allocating a zeroed array is the following:
Both forms check for overflow on the allocation size n * sizeof(...),
and return NULL if that occurred.
These generic allocation functions all emit a stack dump on failure when used
without __GFP_NOWARN so there is no use in emitting an additional failure
message when NULL is returned.
15) The inline disease
----------------------
......
.. SPDX-License-Identifier: GPL-2.0
.. _deprecated:
=====================================================================
Deprecated Interfaces, Language Features, Attributes, and Conventions
=====================================================================
......
......@@ -62,7 +62,7 @@ Legal Issues
The Linux kernel source code is released under the GPL. Please see the file
COPYING in the main directory of the source tree. The Linux kernel licensing
rules and how to use `SPDX <https://spdx.org/>`_ identifiers in source code are
descibed in :ref:`Documentation/process/license-rules.rst <kernel_licensing>`.
described in :ref:`Documentation/process/license-rules.rst <kernel_licensing>`.
If you have further questions about the license, please contact a lawyer, and do
not ask on the Linux kernel mailing list. The people on the mailing lists are
not lawyers, and you should not rely on their statements on legal matters.
......
......@@ -95,18 +95,6 @@ On-line docs
[...]. This paper examines some common problems for
submitting larger changes and some strategies to avoid problems.
* Title: **Overview of the Virtual File System**
:Author: Richard Gooch.
:URL: http://www.mjmwired.net/kernel/Documentation/filesystems/vfs.txt
:Date: 2007
:Keywords: VFS, File System, mounting filesystems, opening files,
dentries, dcache.
:Description: Brief introduction to the Linux Virtual File System.
What is it, how it works, operations taken when opening a file or
mounting a file system and description of important data
structures explaining the purpose of each of their entries.
* Title: **Linux Device Drivers, Third Edition**
:Author: Jonathan Corbet, Alessandro Rubini, Greg Kroah-Hartman
......
......@@ -234,13 +234,13 @@ kernel, can be broken down into:
|
2. Not recommended licenses:
2. Deprecated licenses:
These licenses should only be used for existing code or for importing
code from a different project. These licenses are available from the
directory::
LICENSES/other/
LICENSES/deprecated/
in the kernel source tree.
......@@ -250,14 +250,14 @@ kernel, can be broken down into:
Examples::
LICENSES/other/ISC
LICENSES/deprecated/ISC
Contains the Internet Systems Consortium license text and the required
metatags::
LICENSES/other/ZLib
LICENSES/deprecated/GPL-1.0
Contains the ZLIB license text and the required metatags.
Contains the GPL version 1 license text and the required metatags.
Metatags:
......@@ -281,7 +281,56 @@ kernel, can be broken down into:
|
3. _`Exceptions`:
3. Dual Licensing Only
These licenses should only be used to dual license code with another
license in addition to a preferred license. These licenses are available
from the directory::
LICENSES/dual/
in the kernel source tree.
The files in this directory contain the full license text and
`Metatags`_. The file names are identical to the SPDX license
identifier which shall be used for the license in source files.
Examples::
LICENSES/dual/MPL-1.1
Contains the Mozilla Public License version 1.1 license text and the
required metatags::
LICENSES/dual/Apache-2.0
Contains the Apache License version 2.0 license text and the required
metatags.
Metatags:
The metatag requirements for 'other' licenses are identical to the
requirements of the `Preferred licenses`_.
File format example::
Valid-License-Identifier: MPL-1.1
SPDX-URL: https://spdx.org/licenses/MPL-1.1.html
Usage-Guide:
Do NOT use. The MPL-1.1 is not GPL2 compatible. It may only be used for
dual-licensed files where the other license is GPL2 compatible.
If you end up using this it MUST be used together with a GPL2 compatible
license using "OR".
To use the Mozilla Public License version 1.1 put the following SPDX
tag/value pair into a comment according to the placement guidelines in
the licensing rules documentation:
SPDX-License-Identifier: MPL-1.1
License-Text:
Full license text
|
4. _`Exceptions`:
Some licenses can be amended with exceptions which grant certain rights
which the original license does not. These exceptions are available
......
......@@ -943,7 +943,7 @@ have on your keyring::
Next, open the `PGP pathfinder`_. In the "From" field, paste the key
fingerprint of Linus Torvalds from the output above. In the "To" field,
paste they key-id you found via ``gpg --search`` of the unknown key, and
paste the key-id you found via ``gpg --search`` of the unknown key, and
check the results:
- `Finding paths to Linus`_
......
......@@ -60,8 +60,8 @@ not in any lower subdirectory.
To create a patch for a single file, it is often sufficient to do::
SRCTREE= linux
MYFILE= drivers/net/mydriver.c
SRCTREE=linux
MYFILE=drivers/net/mydriver.c
cd $SRCTREE
cp $MYFILE $MYFILE.orig
......@@ -73,7 +73,7 @@ To create a patch for multiple files, you should unpack a "vanilla",
or unmodified kernel source tree, and generate a ``diff`` against your
own source tree. For example::
MYSRC= /devel/linux
MYSRC=/devel/linux
tar xvfz linux-3.19.tar.gz
mv linux-3.19 linux-3.19-vanilla
......@@ -545,10 +545,40 @@ person it names - but it should indicate that this person was copied on the
patch. This tag documents that potentially interested parties
have been included in the discussion.
A Co-developed-by: states that the patch was also created by another developer
along with the original author. This is useful at times when multiple people
work on a single patch. Note, this person also needs to have a Signed-off-by:
line in the patch as well.
Co-developed-by: states that the patch was co-created by multiple developers;
it is a used to give attribution to co-authors (in addition to the author
attributed by the From: tag) when several people work on a single patch. Since
Co-developed-by: denotes authorship, every Co-developed-by: must be immediately
followed by a Signed-off-by: of the associated co-author. Standard sign-off
procedure applies, i.e. the ordering of Signed-off-by: tags should reflect the
chronological history of the patch insofar as possible, regardless of whether
the author is attributed via From: or Co-developed-by:. Notably, the last
Signed-off-by: must always be that of the developer submitting the patch.
Note, the From: tag is optional when the From: author is also the person (and
email) listed in the From: line of the email header.
Example of a patch submitted by the From: author::
<changelog>
Co-developed-by: First Co-Author <first@coauthor.example.org>
Signed-off-by: First Co-Author <first@coauthor.example.org>
Co-developed-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Example of a patch submitted by a Co-developed-by: author::
From: From Author <from@author.example.org>
<changelog>
Co-developed-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
13) Using Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: and Fixes:
......@@ -696,7 +726,7 @@ A couple of example Subjects::
The ``from`` line must be the very first line in the message body,
and has the form:
From: Original Author <author@example.com>
From: Patch Author <author@example.com>
The ``from`` line specifies who will be credited as the author of the
patch in the permanent changelog. If the ``from`` line is missing,
......
......@@ -136,5 +136,5 @@ a high functionality RTC is integrated into the SOC. That system might read
the system clock from the discrete RTC, but use the integrated one for all
other tasks, because of its greater functionality.
Check out tools/testing/selftests/timers/rtctest.c for an example usage of the
Check out tools/testing/selftests/rtc/rtctest.c for an example usage of the
ioctl interface.
......@@ -17,7 +17,7 @@ observed to extract secret information.
For example, in the presence of branch prediction, it is possible for bounds
checks to be ignored by code which is speculatively executed. Consider the
following code:
following code::
int load_array(int *array, unsigned int index)
{
......@@ -27,7 +27,7 @@ following code:
return array[index];
}
Which, on arm64, may be compiled to an assembly sequence such as:
Which, on arm64, may be compiled to an assembly sequence such as::
CMP <index>, #MAX_ARRAY_ELEMS
B.LT less
......@@ -44,7 +44,7 @@ microarchitectural state which can be subsequently measured.
More complex sequences involving multiple dependent memory accesses may
result in sensitive information being leaked. Consider the following
code, building on the prior example:
code, building on the prior example::
int load_dependent_arrays(int *arr1, int *arr2, int index)
{
......@@ -77,7 +77,7 @@ A call to array_index_nospec(index, size) returns a sanitized index
value that is bounded to [0, size) even under cpu speculation
conditions.
This can be used to protect the earlier load_array() example:
This can be used to protect the earlier load_array() example::
int load_array(int *array, unsigned int index)
{
......
......@@ -196,7 +196,7 @@ CAP_LAST_CAP from the kernel.
core_pattern:
core_pattern is used to specify a core dumpfile pattern name.
. max length 128 characters; default value is "core"
. max length 127 characters; default value is "core"
. core_pattern is used as a pattern template for the output filename;
certain string patterns (beginning with '%') are substituted with
their actual values.
......
......@@ -1404,6 +1404,7 @@ trace has provided some very helpful debugging information.
If we prefer function graph output instead of function, we can set
display-graph option::
with echo 1 > options/display-graph
# tracer: irqsoff
......
......@@ -2133,33 +2133,33 @@ The following commonly-used handler.action pairs are available:
the end the event that triggered the snapshot (in this case you
can verify the timestamps between the sched_waking and
sched_switch events, which should match the time displayed in the
global maximum):
# cat /sys/kernel/debug/tracing/snapshot
<...>-2103 [005] d..3 309.873125: sched_switch: prev_comm=cyclictest prev_pid=2103 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120
<idle>-0 [005] d.h3 309.873611: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.873613: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] d..3 309.873616: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19
<...>-2102 [005] d..3 309.873625: sched_switch: prev_comm=cyclictest prev_pid=2102 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120
<idle>-0 [005] d.h3 309.874624: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.874626: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh3 309.874628: sched_waking: comm=cyclictest pid=2103 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.874630: sched_wakeup: comm=cyclictest pid=2103 prio=19 target_cpu=005
<idle>-0 [005] d..3 309.874633: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19
<idle>-0 [004] d.h3 309.874757: sched_waking: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004
<idle>-0 [004] dNh4 309.874762: sched_wakeup: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004
<idle>-0 [004] d..3 309.874766: sched_switch: prev_comm=swapper/4 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=gnome-terminal- next_pid=1699 next_prio=120
gnome-terminal--1699 [004] d.h2 309.874941: sched_stat_runtime: comm=gnome-terminal- pid=1699 runtime=180706 [ns] vruntime=1126870572 [ns]
<idle>-0 [003] d.s4 309.874956: sched_waking: comm=rcu_sched pid=9 prio=120 target_cpu=007
<idle>-0 [003] d.s5 309.874960: sched_wake_idle_without_ipi: cpu=7
<idle>-0 [003] d.s5 309.874961: sched_wakeup: comm=rcu_sched pid=9 prio=120 target_cpu=007
<idle>-0 [007] d..3 309.874963: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=rcu_sched next_pid=9 next_prio=120
rcu_sched-9 [007] d..3 309.874973: sched_stat_runtime: comm=rcu_sched pid=9 runtime=13646 [ns] vruntime=22531430286 [ns]
rcu_sched-9 [007] d..3 309.874978: sched_switch: prev_comm=rcu_sched prev_pid=9 prev_prio=120 prev_state=R+ ==> next_comm=swapper/7 next_pid=0 next_prio=120
<...>-2102 [005] d..4 309.874994: sched_migrate_task: comm=cyclictest pid=2103 prio=19 orig_cpu=5 dest_cpu=1
<...>-2102 [005] d..4 309.875185: sched_wake_idle_without_ipi: cpu=1
<idle>-0 [001] d..3 309.875200: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2103 next_prio=19
global maximum)::
# cat /sys/kernel/debug/tracing/snapshot
<...>-2103 [005] d..3 309.873125: sched_switch: prev_comm=cyclictest prev_pid=2103 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120
<idle>-0 [005] d.h3 309.873611: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.873613: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] d..3 309.873616: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19
<...>-2102 [005] d..3 309.873625: sched_switch: prev_comm=cyclictest prev_pid=2102 prev_prio=19 prev_state=D ==> next_comm=swapper/5 next_pid=0 next_prio=120
<idle>-0 [005] d.h3 309.874624: sched_waking: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.874626: sched_wakeup: comm=cyclictest pid=2102 prio=19 target_cpu=005
<idle>-0 [005] dNh3 309.874628: sched_waking: comm=cyclictest pid=2103 prio=19 target_cpu=005
<idle>-0 [005] dNh4 309.874630: sched_wakeup: comm=cyclictest pid=2103 prio=19 target_cpu=005
<idle>-0 [005] d..3 309.874633: sched_switch: prev_comm=swapper/5 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2102 next_prio=19
<idle>-0 [004] d.h3 309.874757: sched_waking: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004
<idle>-0 [004] dNh4 309.874762: sched_wakeup: comm=gnome-terminal- pid=1699 prio=120 target_cpu=004
<idle>-0 [004] d..3 309.874766: sched_switch: prev_comm=swapper/4 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=gnome-terminal- next_pid=1699 next_prio=120
gnome-terminal--1699 [004] d.h2 309.874941: sched_stat_runtime: comm=gnome-terminal- pid=1699 runtime=180706 [ns] vruntime=1126870572 [ns]
<idle>-0 [003] d.s4 309.874956: sched_waking: comm=rcu_sched pid=9 prio=120 target_cpu=007
<idle>-0 [003] d.s5 309.874960: sched_wake_idle_without_ipi: cpu=7
<idle>-0 [003] d.s5 309.874961: sched_wakeup: comm=rcu_sched pid=9 prio=120 target_cpu=007
<idle>-0 [007] d..3 309.874963: sched_switch: prev_comm=swapper/7 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=rcu_sched next_pid=9 next_prio=120
rcu_sched-9 [007] d..3 309.874973: sched_stat_runtime: comm=rcu_sched pid=9 runtime=13646 [ns] vruntime=22531430286 [ns]
rcu_sched-9 [007] d..3 309.874978: sched_switch: prev_comm=rcu_sched prev_pid=9 prev_prio=120 prev_state=R+ ==> next_comm=swapper/7 next_pid=0 next_prio=120
<...>-2102 [005] d..4 309.874994: sched_migrate_task: comm=cyclictest pid=2103 prio=19 orig_cpu=5 dest_cpu=1
<...>-2102 [005] d..4 309.875185: sched_wake_idle_without_ipi: cpu=1
<idle>-0 [001] d..3 309.875200: sched_switch: prev_comm=swapper/1 prev_pid=0 prev_prio=120 prev_state=S ==> next_comm=cyclictest next_pid=2103 next_prio=19
- onchange(var).save(field,.. .)
......@@ -2213,9 +2213,10 @@ The following commonly-used handler.action pairs are available:
following the rest of the fields.
If a snaphot was taken, there is also a message indicating that,
along with the value and event that triggered the snapshot:
along with the value and event that triggered the snapshot::
# cat /sys/kernel/debug/tracing/events/tcp/tcp_probe/hist
# cat /sys/kernel/debug/tracing/events/tcp/tcp_probe/hist
{ dport: 1521 } hitcount: 8
changed: 10 snd_wnd: 35456 srtt: 154262 rcv_wnd: 42112
......@@ -2228,14 +2229,15 @@ The following commonly-used handler.action pairs are available:
{ dport: 443 } hitcount: 211
changed: 10 snd_wnd: 26960 srtt: 17379 rcv_wnd: 28800
Snapshot taken (see tracing/snapshot). Details:
Snapshot taken (see tracing/snapshot). Details::
triggering value { onchange($cwnd) }: 10
triggered by event with key: { dport: 80 }
Totals:
Hits: 414
Entries: 4
Dropped: 0
Totals:
Hits: 414
Entries: 4
Dropped: 0
In the above case, the event that triggered the snapshot has the
key with dport == 80. If you look at the bucket that has 80 as
......@@ -2245,18 +2247,18 @@ The following commonly-used handler.action pairs are available:
the global snapshot).
And finally, looking at the snapshot data should show at or near
the end the event that triggered the snapshot:
# cat /sys/kernel/debug/tracing/snapshot
gnome-shell-1261 [006] dN.3 49.823113: sched_stat_runtime: comm=gnome-shell pid=1261 runtime=49347 [ns] vruntime=1835730389 [ns]
kworker/u16:4-773 [003] d..3 49.823114: sched_switch: prev_comm=kworker/u16:4 prev_pid=773 prev_prio=120 prev_state=R+ ==> next_comm=kworker/3:2 next_pid=135 next_prio=120
gnome-shell-1261 [006] d..3 49.823114: sched_switch: prev_comm=gnome-shell prev_pid=1261 prev_prio=120 prev_state=R+ ==> next_comm=kworker/6:2 next_pid=387 next_prio=120
kworker/3:2-135 [003] d..3 49.823118: sched_stat_runtime: comm=kworker/3:2 pid=135 runtime=5339 [ns] vruntime=17815800388 [ns]
kworker/6:2-387 [006] d..3 49.823120: sched_stat_runtime: comm=kworker/6:2 pid=387 runtime=9594 [ns] vruntime=14589605367 [ns]
kworker/6:2-387 [006] d..3 49.823122: sched_switch: prev_comm=kworker/6:2 prev_pid=387 prev_prio=120 prev_state=R+ ==> next_comm=gnome-shell next_pid=1261 next_prio=120
kworker/3:2-135 [003] d..3 49.823123: sched_switch: prev_comm=kworker/3:2 prev_pid=135 prev_prio=120 prev_state=T ==> next_comm=swapper/3 next_pid=0 next_prio=120
<idle>-0 [004] ..s7 49.823798: tcp_probe: src=10.0.0.10:54326 dest=23.215.104.193:80 mark=0x0 length=32 snd_nxt=0xe3ae2ff5 snd_una=0xe3ae2ecd snd_cwnd=10 ssthresh=2147483647 snd_wnd=28960 srtt=19604 rcv_wnd=29312
the end the event that triggered the snapshot::
# cat /sys/kernel/debug/tracing/snapshot
gnome-shell-1261 [006] dN.3 49.823113: sched_stat_runtime: comm=gnome-shell pid=1261 runtime=49347 [ns] vruntime=1835730389 [ns]
kworker/u16:4-773 [003] d..3 49.823114: sched_switch: prev_comm=kworker/u16:4 prev_pid=773 prev_prio=120 prev_state=R+ ==> next_comm=kworker/3:2 next_pid=135 next_prio=120
gnome-shell-1261 [006] d..3 49.823114: sched_switch: prev_comm=gnome-shell prev_pid=1261 prev_prio=120 prev_state=R+ ==> next_comm=kworker/6:2 next_pid=387 next_prio=120
kworker/3:2-135 [003] d..3 49.823118: sched_stat_runtime: comm=kworker/3:2 pid=135 runtime=5339 [ns] vruntime=17815800388 [ns]
kworker/6:2-387 [006] d..3 49.823120: sched_stat_runtime: comm=kworker/6:2 pid=387 runtime=9594 [ns] vruntime=14589605367 [ns]
kworker/6:2-387 [006] d..3 49.823122: sched_switch: prev_comm=kworker/6:2 prev_pid=387 prev_prio=120 prev_state=R+ ==> next_comm=gnome-shell next_pid=1261 next_prio=120
kworker/3:2-135 [003] d..3 49.823123: sched_switch: prev_comm=kworker/3:2 prev_pid=135 prev_prio=120 prev_state=T ==> next_comm=swapper/3 next_pid=0 next_prio=120
<idle>-0 [004] ..s7 49.823798: tcp_probe: src=10.0.0.10:54326 dest=23.215.104.193:80 mark=0x0 length=32 snd_nxt=0xe3ae2ff5 snd_una=0xe3ae2ecd snd_cwnd=10 ssthresh=2147483647 snd_wnd=28960 srtt=19604 rcv_wnd=29312
3. User space creating a trigger
--------------------------------
......
......@@ -11,3 +11,43 @@ Translations
it_IT/index
ko_KR/index
ja_JP/index
.. _translations_disclaimer:
Disclaimer
----------
Translation's purpose is to ease reading and understanding in languages other
than English. Its aim is to help people who do not understand English or have
doubts about its interpretation. Additionally, some people prefer to read
documentation in their native language, but please bear in mind that the
*only* official documentation is the English one: :ref:`linux_doc`.
It is very unlikely that an update to :ref:`linux_doc` will be propagated
immediately to all translations. Translations' maintainers - and
contributors - follow the evolution of the official documentation and they
maintain translations aligned as much as they can. For this reason there is
no guarantee that a translation is up to date. If what you read in a
translation does not sound right compared to what you read in the code, please
inform the translation maintainer and - if you can - check also the English
documentation.
A translation is not a fork of the official documentation, therefore
translations' users should not find information that differs from the official
English documentation. Any content addition, removal or update, must be
applied to the English documents first. Afterwards and when possible, the
same change should be applied to translations. Translations' maintainers
accept only contributions that are merely translation related (e.g. new
translations, updates, fixes).
Translations try to be as accurate as possible but it is not possible to map
one language directly to all other languages. Each language has its own
grammar and culture, so the translation of an English statement may need to be
adapted to fit a different language. For this reason, when viewing
translations, you may find slight differences that carry the same message but
in a different form.
If you need to communicate with the Linux community but you do not feel
comfortable writing in English, you can ask the translation's maintainers
for help.
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/core-api/memory-allocation.rst <memory_allocation>`
.. _it_memory_allocation:
================================
Guida all'allocazione di memoria
================================
.. warning::
TODO ancora da tradurre
:orphan:
.. note::
This document is maintained by Federico Vaga <federico.vaga@vaga.pv.it>.
If you find any difference between this document and the original file or a
problem with the translation, please contact the maintainer of this file.
Following people helped to translate or review:
Alessia Mantegazza <amantegazza@vaga.pv.it>
.. warning::
The purpose of this file is to be easier to read and understand for Italian
speakers and is not intended as a fork. So, if you have any comments or
updates for this file please try to update the original English file first.
In caso di dubbi sulla correttezza del contenuto di questa traduzione,
l'unico riferimento valido è la documentazione ufficiale in inglese.
Per maggiori informazioni consultate le :ref:`avvertenze <it_disclaimer>`.
......@@ -12,9 +12,9 @@ Come scrivere la documentazione del kernel
.. toctree::
:maxdepth: 1
sphinx.rst
kernel-doc.rst
parse-headers.rst
sphinx
kernel-doc
parse-headers
.. only:: subproject and html
......
......@@ -4,26 +4,49 @@
Traduzione italiana
===================
L'obiettivo di questa traduzione è di rendere più facile la lettura e
la comprensione per chi preferisce leggere in lingua italiana.
Tenete presente che la documentazione di riferimento rimane comunque
quella in lingua inglese: :ref:`linux_doc`
Questa traduzione cerca di essere il più fedele possibile all'originale ma
è ovvio che alcune frasi vadano trasformate: non aspettatevi una traduzione
letterale. Quando possibile, si eviteranno gli inglesismi ed al loro posto
verranno utilizzate le corrispettive parole italiane.
:manutentore: Federico Vaga <federico.vaga@vaga.pv.it>
Se notate che la traduzione non è più aggiornata potete contattare
direttamente il manutentore della traduzione italiana.
.. _it_disclaimer:
Se notate che la documentazione contiene errori o dimenticanze, allora
verificate la documentazione di riferimento in lingua inglese. Se il problema
è presente anche nella documentazione di riferimento, contattate il suo
manutentore. Se avete problemi a scrivere in inglese, potete comunque
riportare il problema al manutentore della traduzione italiana.
Avvertenze
==========
Manutentore della traduzione italiana: Federico Vaga <federico.vaga@vaga.pv.it>
L'obiettivo di questa traduzione è di rendere più facile la lettura e
la comprensione per chi non capisce l'inglese o ha dubbi sulla sua
interpretazione, oppure semplicemente per chi preferisce leggere in lingua
italiana. Tuttavia, tenete ben presente che l'*unica* documentazione
ufficiale è quella in lingua inglese: :ref:`linux_doc`
La propagazione simultanea a tutte le traduzioni di una modifica in
:ref:`linux_doc` è altamente improbabile. I manutentori delle traduzioni -
e i contributori - seguono l'evolversi della documentazione ufficiale e
cercano di mantenere le rispettive traduzioni allineate nel limite del
possibile. Per questo motivo non c'è garanzia che una traduzione sia
aggiornata all'ultima modifica. Se quello che leggete in una traduzione
non corrisponde a quello che leggete nel codice, informate il manutentore
della traduzione e - se potete - verificate anche la documentazione in
inglese.
Una traduzione non è un *fork* della documentazione ufficiale, perciò gli
utenti non vi troveranno alcuna informazione diversa rispetto alla versione
ufficiale. Ogni aggiunta, rimozione o modifica dei contenuti deve essere
fatta prima nei documenti in inglese. In seguito, e quando è possibile, la
stessa modifica dovrebbe essere applicata anche alle traduzioni. I manutentori
delle traduzioni accettano contributi che interessano prettamente l'attività
di traduzione (per esempio, nuove traduzioni, aggiornamenti, correzioni).
Le traduzioni cercano di essere il più possibile accurate ma non è possibile
mappare direttamente una lingua in un'altra. Ogni lingua ha la sua grammatica
e una sua cultura alle spalle, quindi la traduzione di una frase in inglese
potrebbe essere modificata per adattarla all'italiano. Per questo motivo,
quando leggete questa traduzione, potreste trovare alcune differenze di forma
ma che trasmettono comunque il messaggio originale. Nonostante la grande
diffusione di inglesismi nella lingua parlata, quando possibile, questi
verranno sostituiti dalle corrispettive parole italiane
Se avete bisogno d'aiuto per comunicare con la comunità Linux ma non vi sentite
a vostro agio nello scrivere in inglese, potete chiedere aiuto al manutentore
della traduzione.
La documentazione del kernel Linux
==================================
......@@ -47,9 +70,7 @@ I seguenti documenti descrivono la licenza usata nei sorgenti del kernel Linux
(GPLv2), come licenziare i singoli file; inoltre troverete i riferimenti al
testo integrale della licenza.
.. warning::
TODO ancora da tradurre
* :ref:`it_kernel_licensing`
Documentazione per gli utenti
-----------------------------
......@@ -90,10 +111,6 @@ vostre modifiche molto più semplice
doc-guide/index
kernel-hacking/index
.. warning::
TODO ancora da tradurre
Documentazione della API del kernel
-----------------------------------
......
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
.. _it_netdev-FAQ:
==========
netdev FAQ
==========
.. warning::
TODO ancora da tradurre
......@@ -233,10 +233,12 @@ Le etichette in uso più comuni sono:
:ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
Codice che non presenta una firma appropriata non potrà essere integrato.
- Co-developed-by: indica che la patch è stata sviluppata anche da un altro
sviluppatore assieme all'autore originale. Questo è utile quando più
persone lavorano sulla stessa patch. Da notare che questa persona deve
avere anche una riga "Signed-off-by:" nella patch.
- Co-developed-by: indica che la patch è stata cosviluppata da diversi
sviluppatori; viene usato per assegnare più autori (in aggiunta a quello
associato all'etichetta From:) quando più persone lavorano ad una patch.
Ogni Co-developed-by: dev'essere seguito immediatamente da un Signed-off-by:
del corrispondente coautore. Maggiori dettagli ed esempi sono disponibili
in :ref:`Documentation/translations/it_IT/process/submitting-patches.rst <it_submittingpatches>`.
- Acked-by: indica il consenso di un altro sviluppatore (spesso il manutentore
del codice in oggetto) all'integrazione della patch nel kernel.
......
......@@ -859,7 +859,8 @@ racchiusa in #ifdef, potete usare printk(KERN_DEBUG ...).
Il kernel fornisce i seguenti assegnatori ad uso generico:
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), e vzalloc().
Per maggiori informazioni, consultate la documentazione dell'API.
Per maggiori informazioni, consultate la documentazione dell'API:
:ref:`Documentation/translations/it_IT/core-api/memory-allocation.rst <it_memory_allocation>`
Il modo preferito per passare la dimensione di una struttura è il seguente:
......@@ -890,6 +891,11 @@ Il modo preferito per assegnare un vettore a zero è il seguente:
Entrambe verificano la condizione di overflow per la dimensione
d'assegnamento n * sizeof(...), se accade ritorneranno NULL.
Questi allocatori generici producono uno *stack dump* in caso di fallimento
a meno che non venga esplicitamente specificato __GFP_NOWARN. Quindi, nella
maggior parte dei casi, è inutile stampare messaggi aggiuntivi quando uno di
questi allocatori ritornano un puntatore NULL.
15) Il morbo inline
-------------------
......
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/deprecated.rst <deprecated>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_deprecated:
==============================================================================
Interfacce deprecate, caratteristiche del linguaggio, attributi, e convenzioni
==============================================================================
In un mondo perfetto, sarebbe possibile prendere tutti gli usi di
un'interfaccia deprecata e convertirli in quella nuova, e così sarebbe
possibile rimuovere la vecchia interfaccia in un singolo ciclo di sviluppo.
Tuttavia, per via delle dimensioni del kernel, la gerarchia dei manutentori e
le tempistiche, non è sempre possibile fare questo tipo di conversione tutta
in una volta. Questo significa che nuove istanze di una vecchia interfaccia
potrebbero aggiungersi al kernel proprio quando si sta cercando di rimuoverle,
aumentando così il carico di lavoro. Al fine di istruire gli sviluppatori su
cosa è considerato deprecato (e perché), è stata create la seguente lista a cui
fare riferimento quando qualcuno propone modifiche che usano cose deprecate.
__deprecated
------------
Nonostante questo attributo marchi visibilmente un interfaccia come deprecata,
`non produce più alcun avviso durante la compilazione
<https://git.kernel.org/linus/771c035372a036f83353eef46dbb829780330234>`_
perché uno degli obiettivi del kernel è quello di compilare senza avvisi;
inoltre, nessuno stava agendo per rimuovere queste interfacce. Nonostante l'uso
di `__deprecated` in un file d'intestazione sia opportuno per segnare una
interfaccia come 'vecchia', questa non è una soluzione completa. L'interfaccia
deve essere rimossa dal kernel, o aggiunta a questo documento per scoraggiarne
l'uso.
Calcoli codificati negli argomenti di un allocatore
----------------------------------------------------
Il calcolo dinamico delle dimensioni (specialmente le moltiplicazioni) non
dovrebbero essere fatto negli argomenti di funzioni di allocazione di memoria
(o simili) per via del rischio di overflow. Questo può portare a valori più
piccoli di quelli che il chiamante si aspettava. L'uso di questo modo di
allocare può portare ad un overflow della memoria di heap e altri
malfunzionamenti. (Si fa eccezione per valori numerici per i quali il
compilatore può generare avvisi circa un potenziale overflow. Tuttavia usare
i valori numerici come suggerito di seguito è innocuo).
Per esempio, non usate ``count * size`` come argomento::
foo = kmalloc(count * size, GFP_KERNEL);
Al suo posto, si dovrebbe usare l'allocatore a due argomenti::
foo = kmalloc_array(count, size, GFP_KERNEL);
Se questo tipo di allocatore non è disponibile, allora dovrebbero essere usate
le funzioni del tipo *saturate-on-overflow*::
bar = vmalloc(array_size(count, size));
Un altro tipico caso da evitare è quello di calcolare la dimensione di una
struttura seguita da un vettore di altre strutture, come nel seguente caso::
header = kzalloc(sizeof(*header) + count * sizeof(*header->item),
GFP_KERNEL);
Invece, usate la seguente funzione::
header = kzalloc(struct_size(header, item, count), GFP_KERNEL);
Per maggiori dettagli fate riferimento a :c:func:`array_size`,
:c:func:`array3_size`, e :c:func:`struct_size`, così come la famiglia di
funzioni :c:func:`check_add_overflow` e :c:func:`check_mul_overflow`.
simple_strtol(), simple_strtoll(), simple_strtoul(), simple_strtoull()
----------------------------------------------------------------------
Le funzioni :c:func:`simple_strtol`, :c:func:`simple_strtoll`,
:c:func:`simple_strtoul`, e :c:func:`simple_strtoull` ignorano volutamente
i possibili overflow, e questo può portare il chiamante a generare risultati
inaspettati. Le rispettive funzioni :c:func:`kstrtol`, :c:func:`kstrtoll`,
:c:func:`kstrtoul`, e :c:func:`kstrtoull` sono da considerarsi le corrette
sostitute; tuttavia va notato che queste richiedono che la stringa sia
terminata con il carattere NUL o quello di nuova riga.
strcpy()
--------
La funzione :c:func:`strcpy` non fa controlli agli estremi del buffer
di destinazione. Questo può portare ad un overflow oltre i limiti del
buffer e generare svariati tipi di malfunzionamenti. Nonostante l'opzione
`CONFIG_FORTIFY_SOURCE=y` e svariate opzioni del compilatore aiutano
a ridurne il rischio, non c'è alcuna buona ragione per continuare ad usare
questa funzione. La versione sicura da usare è :c:func:`strscpy`.
strncpy() su stringe terminate con NUL
--------------------------------------
L'utilizzo di :c:func:`strncpy` non fornisce alcuna garanzia sul fatto che
il buffer di destinazione verrà terminato con il carattere NUL. Questo
potrebbe portare a diversi overflow di lettura o altri malfunzionamenti
causati, appunto, dalla mancanza del terminatore. Questa estende la
terminazione nel buffer di destinazione quando la stringa d'origine è più
corta; questo potrebbe portare ad una penalizzazione delle prestazioni per
chi usa solo stringe terminate. La versione sicura da usare è
:c:func:`strscpy`. (chi usa :c:func:`strscpy` e necessita di estendere la
terminazione con NUL deve aggiungere una chiamata a :c:func:`memset`)
Se il chiamate no usa stringhe terminate con NUL, allore :c:func:`strncpy()`
può continuare ad essere usata, ma i buffer di destinazione devono essere
marchiati con l'attributo `__nonstring <https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html>`_
per evitare avvisi durante la compilazione.
strlcpy()
---------
La funzione :c:func:`strlcpy`, per prima cosa, legge interamente il buffer di
origine, magari leggendo più di quanto verrà effettivamente copiato. Questo
è inefficiente e può portare a overflow di lettura quando la stringa non è
terminata con NUL. La versione sicura da usare è :c:func:`strscpy`.
Vettori a dimensione variabile (VLA)
------------------------------------
Usare VLA sullo stack produce codice molto peggiore rispetto a quando si usano
vettori a dimensione fissa. Questi `problemi di prestazioni <https://git.kernel.org/linus/02361bc77888>`_,
tutt'altro che banali, sono già un motivo valido per eliminare i VLA; in
aggiunta sono anche un problema per la sicurezza. La crescita dinamica di un
vettore nello stack potrebbe eccedere la memoria rimanente in tale segmento.
Questo può portare a dei malfunzionamenti, potrebbe sovrascrivere
dati importanti alla fine dello stack (quando il kernel è compilato senza
`CONFIG_THREAD_INFO_IN_TASK=y`), o sovrascrivere un pezzo di memoria adiacente
allo stack (quando il kernel è compilato senza `CONFIG_VMAP_STACK=y`).
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/kernel-enforcement-statement.rst <process_statement_kernel>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_process_statement_kernel:
Applicazione della licenza sul kernel Linux
===========================================
.. warning::
Come sviluppatori del kernel Linux, abbiamo un certo interessa su come il
nostro software viene usato e su come la sua licenza viene fatta rispettare.
Il rispetto reciproco degli obblighi di condivisione della GPL-2.0 è
fondamentale per la sostenibilità di lungo periodo del nostro software e
della nostra comunità.
Benché ognuno abbia il diritto a far rispettare il diritto d'autore per i
propri contributi alla nostra comunità, condividiamo l'interesse a far si che
ogni azione individuale nel far rispettare i propri diritti sia condotta in
modo da portare beneficio alla comunità e che non abbia, involontariamente,
impatti negativi sulla salute e la crescita del nostro ecosistema software.
Al fine di scoraggiare l'esecuzione di azioni inutili, concordiamo che è nel
migliore interesse della nostra comunità di sviluppo di impegnarci nel
rispettare i seguenti obblighi nei confronti degli utenti del kernel Linux
per conto nostro e di qualsiasi successore ai nostri interessi sul diritto
d'autore:
Malgrado le clausole di risoluzione della licenza GPL-2.0, abbiamo
concordato che è nel migliore interesse della nostra comunità di sviluppo
adottare le seguenti disposizioni della GPL-3.0 come permessi aggiuntivi
alla nostra licenza nei confronti di qualsiasi affermazione non difensiva
di diritti sulla licenza.
In ogni caso, se cessano tutte le violazioni di questa Licenza, allora
la tua licenza da parte di un dato detentore del copyright viene
ripristinata (a) in via cautelativa, a meno che e fino a quando il
detentore del copyright non cessa esplicitamente e definitivamente
la tua licenza, e (b) in via permanente se il detentore del copyright
non ti notifica in alcun modo la violazione entro 60 giorni dalla
cessazione della licenza.
Inoltre, la tua licenza da parte di un dato detentore del copyright
viene ripristinata in maniera permanente se il detentore del copyright
ti notifica la violazione in maniera adeguata, se questa è la prima
volta che ricevi una notifica di violazione di questa Licenza (per
qualunque Programma) dallo stesso detentore di copyright, e se rimedi
alla violazione entro 30 giorni dalla data di ricezione della notifica
di violazione.
Fornendo queste garanzie, abbiamo l'intenzione di incoraggiare l'uso del
software. Vogliamo che le aziende e le persone usino, modifichino e
distribuiscano a questo software. Vogliamo lavorare con gli utenti in modo
aperto e trasparente per eliminare ogni incertezza circa le nostre aspettative
sul rispetto o l'ottemperanza alla licenza che possa limitare l'uso del nostro
software. Vediamo l'azione legale come ultima spiaggia, da avviare solo quando
gli altri sforzi della comunità hanno fallito nel risolvere il problema.
Per finire, una volta che un problema di non rispetto della licenza viene
risolto, speriamo che gli utenti si sentano i benvenuti ad aggregarsi a noi
nello sviluppo di questo progetto. Lavorando assieme, saremo più forti.
Ad eccezione deve specificato, parliamo per noi stessi, e non per una qualsiasi
azienda per la quale lavoriamo oggi, o per cui abbiamo lavorato in passato, o
lavoreremo in futuro.
TODO ancora da tradurre
- Laura Abbott
- Bjorn Andersson (Linaro)
- Andrea Arcangeli
- Neil Armstrong
- Jens Axboe
- Pablo Neira Ayuso
- Khalid Aziz
- Ralf Baechle
- Felipe Balbi
- Arnd Bergmann
- Ard Biesheuvel
- Tim Bird
- Paolo Bonzini
- Christian Borntraeger
- Mark Brown (Linaro)
- Paul Burton
- Javier Martinez Canillas
- Rob Clark
- Kees Cook (Google)
- Jonathan Corbet
- Dennis Dalessandro
- Vivien Didelot (Savoir-faire Linux)
- Hans de Goede
- Mel Gorman (SUSE)
- Sven Eckelmann
- Alex Elder (Linaro)
- Fabio Estevam
- Larry Finger
- Bhumika Goyal
- Andy Gross
- Juergen Gross
- Shawn Guo
- Ulf Hansson
- Stephen Hemminger (Microsoft)
- Tejun Heo
- Rob Herring
- Masami Hiramatsu
- Michal Hocko
- Simon Horman
- Johan Hovold (Hovold Consulting AB)
- Christophe JAILLET
- Olof Johansson
- Lee Jones (Linaro)
- Heiner Kallweit
- Srinivas Kandagatla
- Jan Kara
- Shuah Khan (Samsung)
- David Kershner
- Jaegeuk Kim
- Namhyung Kim
- Colin Ian King
- Jeff Kirsher
- Greg Kroah-Hartman (Linux Foundation)
- Christian König
- Vinod Koul
- Krzysztof Kozlowski
- Viresh Kumar
- Aneesh Kumar K.V
- Julia Lawall
- Doug Ledford
- Chuck Lever (Oracle)
- Daniel Lezcano
- Shaohua Li
- Xin Long
- Tony Luck
- Catalin Marinas (Arm Ltd)
- Mike Marshall
- Chris Mason
- Paul E. McKenney
- Arnaldo Carvalho de Melo
- David S. Miller
- Ingo Molnar
- Kuninori Morimoto
- Trond Myklebust
- Martin K. Petersen (Oracle)
- Borislav Petkov
- Jiri Pirko
- Josh Poimboeuf
- Sebastian Reichel (Collabora)
- Guenter Roeck
- Joerg Roedel
- Leon Romanovsky
- Steven Rostedt (VMware)
- Frank Rowand
- Ivan Safonov
- Anna Schumaker
- Jes Sorensen
- K.Y. Srinivasan
- David Sterba (SUSE)
- Heiko Stuebner
- Jiri Kosina (SUSE)
- Willy Tarreau
- Dmitry Torokhov
- Linus Torvalds
- Thierry Reding
- Rik van Riel
- Luis R. Rodriguez
- Geert Uytterhoeven (Glider bvba)
- Eduardo Valentin (Amazon.com)
- Daniel Vetter
- Linus Walleij
- Richard Weinberger
- Dan Williams
- Rafael J. Wysocki
- Arvind Yadav
- Masahiro Yamada
- Wei Yongjun
- Lv Zheng
- Marc Zyngier (Arm Ltd)
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/license-rules.rst <kernel_licensing>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_kernel_licensing:
Regole per licenziare il kernel Linux
=====================================
Il kernel Linux viene rilasciato sotto i termini definiti dalla seconda
versione della licenza *GNU General Public License* (GPL-2.0), di cui una
copia è disponibile nel file LICENSES/preferred/GPL-2.0; a questo si
aggiunge eccezione per le chiamate di sistema come descritto in
LICENSES/exceptions/Linux-syscall-note; tutto ciò è descritto nel file COPYING.
Questo documento fornisce una descrizione su come ogni singolo file sorgente
debba essere licenziato per far si che sia chiaro e non ambiguo. Questo non
sostituisce la licenza del kernel.
La licenza descritta nel file COPYING si applica ai sorgenti del kernel nella
loro interezza, quindi i singoli file sorgenti possono avere diverse licenze ma
devono essere compatibili con la GPL-2.0::
GPL-1.0+ : GNU General Public License v1.0 o successiva
GPL-2.0+ : GNU General Public License v2.0 o successiva
LGPL-2.0 : GNU Library General Public License v2
LGPL-2.0+ : GNU Library General Public License v2 o successiva
LGPL-2.1 : GNU Lesser General Public License v2.1
LGPL-2.1+ : GNU Lesser General Public License v2.1 o successiva
A parte questo, i singolo file possono essere forniti con una doppia licenza,
per esempio con una delle varianti compatibili della GPL e alternativamente con
una licenza permissiva come BSD, MIT eccetera.
I file d'intestazione per l'API verso lo spazio utente (UAPI) descrivono
le interfacce usate dai programmi, e per questo sono un caso speciale.
Secondo le note nel file COPYING, le chiamate di sistema sono un chiaro
confine oltre il quale non si estendono i requisiti della GPL per quei
programmi che le usano per comunicare con il kernel. Dato che i file
d'intestazione UAPI devono poter essere inclusi nei sorgenti di un
qualsiasi programma eseguibile sul kernel Linux, questi meritano
un'eccezione documentata da una clausola speciale.
Il modo più comune per indicare la licenza dei file sorgenti è quello di
aggiungere il corrispondente blocco di testo come commento in testa a detto
file. Per via della formattazione, dei refusi, eccetera, questi blocchi di
testo sono difficili da identificare dagli strumenti usati per verificare il
rispetto delle licenze.
Un'alternativa ai blocchi di testo è data dall'uso degli identificatori
*Software Package Data Exchange* (SPDX) in ogni file sorgente. Gli
identificatori di licenza SPDX sono analizzabili dalle macchine e sono precisi
simboli stenografici che identificano la licenza sotto la quale viene
licenziato il file che lo include. Gli identificatori di licenza SPDX sono
gestiti del gruppo di lavoro SPDX presso la Linux Foundation e sono stati
concordati fra i soci nell'industria, gli sviluppatori di strumenti, e i
rispettivi gruppi legali. Per maggiori informazioni, consultate
https://spdx.org/
Il kernel Linux richiede un preciso identificatore SPDX in tutti i file
sorgenti. Gli identificatori validi verranno spiegati nella sezione
`Identificatori di licenza`_ e sono stati copiati dalla lista ufficiale di
licenze SPDX assieme al rispettivo testo come mostrato in
https://spdx.org/licenses/.
Sintassi degli identificatori di licenza
----------------------------------------
1. Posizionamento:
L'identificativo di licenza SPDX dev'essere posizionato come prima riga
possibile di un file che possa contenere commenti. Per la maggior parte
dei file questa è la prima riga, fanno eccezione gli script che richiedono
come prima riga '#!PATH_TO_INTERPRETER'. Per questi script l'identificativo
SPDX finisce nella seconda riga.
|
2. Stile:
L'identificativo di licenza SPDX viene aggiunto sotto forma di commento.
Lo stile del commento dipende dal tipo di file::
sorgenti C: // SPDX-License-Identifier: <SPDX License Expression>
intestazioni C: /* SPDX-License-Identifier: <SPDX License Expression> */
ASM: /* SPDX-License-Identifier: <SPDX License Expression> */
scripts: # SPDX-License-Identifier: <SPDX License Expression>
.rst: .. SPDX-License-Identifier: <SPDX License Expression>
.dts{i}: // SPDX-License-Identifier: <SPDX License Expression>
Se un particolare programma non dovesse riuscire a gestire lo stile
principale per i commenti, allora dev'essere usato il meccanismo accettato
dal programma. Questo è il motivo per cui si ha "/\* \*/" nei file
d'intestazione C. Notammo che 'ld' falliva nell'analizzare i commenti del
C++ nei file .lds che venivano prodotti. Oggi questo è stato corretto,
ma ci sono in giro ancora vecchi programmi che non sono in grado di
gestire lo stile dei commenti del C++.
|
3. Sintassi:
Una <espressione di licenza SPDX> può essere scritta usando l'identificatore
SPDX della licenza come indicato nella lista di licenze SPDX, oppure la
combinazione di due identificatori SPDX separati da "WITH" per i casi
eccezionali. Quando si usano più licenze l'espressione viene formata da
sottoespressioni separate dalle parole chiave "AND", "OR" e racchiuse fra
parentesi tonde "(", ")".
Gli identificativi di licenza per licenze come la [L]GPL che si avvalgono
dell'opzione 'o successive' si formano aggiungendo alla fine il simbolo "+"
per indicare l'opzione 'o successive'.::
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: LGPL-2.1+
WITH dovrebbe essere usato quando sono necessarie delle modifiche alla
licenza. Per esempio, la UAPI del kernel linux usa l'espressione::
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
// SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note
Altri esempi di usi di WITH all'interno del kernel sono::
// SPDX-License-Identifier: GPL-2.0 WITH mif-exception
// SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0
Le eccezioni si possono usare solo in combinazione con identificatori di
licenza. Gli identificatori di licenza riconosciuti sono elencati nei
corrispondenti file d'eccezione. Per maggiori dettagli consultate
`Eccezioni`_ nel capitolo `Identificatori di licenza`_
La parola chiave OR dovrebbe essere usata solo quando si usa una doppia
licenza e solo una dev'essere scelta. Per esempio, alcuni file dtsi sono
disponibili con doppia licenza::
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
Esempi dal kernel di espressioni per file licenziati con doppia licenza
sono::
// SPDX-License-Identifier: GPL-2.0 OR MIT
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
// SPDX-License-Identifier: GPL-2.0 OR MPL-1.1
// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT
// SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL
La parola chiave AND dovrebbe essere usata quando i termini di più licenze
si applicano ad un file. Per esempio, quando il codice viene preso da
un altro progetto il quale da i permessi per aggiungerlo nel kernel ma
richiede che i termini originali della licenza rimangano intatti::
// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT
Di seguito, un altro esempio dove entrambe i termini di licenza devono
essere rispettati::
// SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+
Identificatori di licenza
-------------------------
Le licenze attualmente in uso, così come le licenze aggiunte al kernel, possono
essere categorizzate in:
1. _`Licenze raccomandate`:
Ovunque possibile le licenze qui indicate dovrebbero essere usate perché
pienamente compatibili e molto usate. Queste licenze sono disponibile nei
sorgenti del kernel, nella cartella::
LICENSES/preferred/
I file in questa cartella contengono il testo completo della licenza e i
`Metatag`_. Il nome di questi file è lo stesso usato come identificatore
di licenza SPDX e che deve essere usato nei file sorgenti.
Esempi::
LICENSES/preferred/GPL-2.0
Contiene il testo della seconda versione della licenza GPL e i metatag
necessari::
LICENSES/preferred/MIT
Contiene il testo della licenza MIT e i metatag necessari.
_`Metatag`:
I seguenti metatag devono essere presenti in un file di licenza:
- Valid-License-Identifier:
Una o più righe che dichiarano quali identificatori di licenza sono validi
all'interno del progetto per far riferimento alla licenza in questione.
Solitamente, questo è un unico identificatore valido, ma per esempio le
licenze che permettono l'opzione 'o successive' hanno due identificatori
validi.
- SPDX-URL:
L'URL della pagina SPDX che contiene informazioni aggiuntive riguardanti
la licenza.
- Usage-Guidance:
Testo in formato libero per dare suggerimenti agli utenti. Il testo deve
includere degli esempi su come usare gli identificatori di licenza SPDX
in un file sorgente in conformità con le linea guida in
`Sintassi degli identificatori di licenza`_.
- License-Text:
Tutto il testo che compare dopo questa etichetta viene trattato
come se fosse parte del testo originale della licenza.
Esempi::
Valid-License-Identifier: GPL-2.0
Valid-License-Identifier: GPL-2.0+
SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
Usage-Guide:
To use this license in source code, put one of the following SPDX
tag/value pairs into a comment according to the placement
guidelines in the licensing rules documentation.
For 'GNU General Public License (GPL) version 2 only' use:
SPDX-License-Identifier: GPL-2.0
For 'GNU General Public License (GPL) version 2 or any later version' use:
SPDX-License-Identifier: GPL-2.0+
License-Text:
Full license text
::
SPDX-License-Identifier: MIT
SPDX-URL: https://spdx.org/licenses/MIT.html
Usage-Guide:
To use this license in source code, put the following SPDX
tag/value pair into a comment according to the placement
guidelines in the licensing rules documentation.
SPDX-License-Identifier: MIT
License-Text:
Full license text
|
2. Licenze non raccomandate:
Questo tipo di licenze dovrebbero essere usate solo per codice già esistente
o quando si prende codice da altri progetti. Le licenze sono disponibili
nei sorgenti del kernel nella cartella::
LICENSES/other/
I file in questa cartella contengono il testo completo della licenza e i
`Metatag`_. Il nome di questi file è lo stesso usato come identificatore
di licenza SPDX e che deve essere usato nei file sorgenti.
Esempi::
LICENSES/other/ISC
Contiene il testo della licenza Internet System Consortium e i suoi
metatag::
LICENSES/other/ZLib
Contiene il testo della licenza ZLIB e i suoi metatag.
Metatag:
I metatag necessari per le 'altre' ('other') licenze sono gli stessi
di usati per le `Licenze raccomandate`_.
Esempio del formato del file::
Valid-License-Identifier: ISC
SPDX-URL: https://spdx.org/licenses/ISC.html
Usage-Guide:
Usage of this license in the kernel for new code is discouraged
and it should solely be used for importing code from an already
existing project.
To use this license in source code, put the following SPDX
tag/value pair into a comment according to the placement
guidelines in the licensing rules documentation.
SPDX-License-Identifier: ISC
License-Text:
Full license text
|
3. _`Eccezioni`:
Alcune licenze possono essere corrette con delle eccezioni che forniscono
diritti aggiuntivi. Queste eccezioni sono disponibili nei sorgenti del
kernel nella cartella::
LICENSES/exceptions/
I file in questa cartella contengono il testo completo dell'eccezione e i
`Metatag per le eccezioni`_.
Esempi::
LICENSES/exceptions/Linux-syscall-note
Contiene la descrizione dell'eccezione per le chiamate di sistema Linux
così come documentato nel file COPYING del kernel Linux; questo viene usato
per i file d'intestazione per la UAPI. Per esempio
/\* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note \*/::
LICENSES/exceptions/GCC-exception-2.0
Contiene la 'eccezione di linking' che permette di collegare qualsiasi
binario, indipendentemente dalla sua licenza, con un compilato il cui file
sorgente è marchiato con questa eccezione. Questo è necessario per creare
eseguibili dai sorgenti che non sono compatibili con la GPL.
_`Metatag per le eccezioni`:
Un file contenente un'eccezione deve avere i seguenti metatag:
- SPDX-Exception-Identifier:
Un identificatore d'eccezione che possa essere usato in combinazione con
un identificatore di licenza SPDX.
- SPDX-URL:
L'URL della pagina SPDX che contiene informazioni aggiuntive riguardanti
l'eccezione.
- SPDX-Licenses:
Una lista di licenze SPDX separate da virgola, che possono essere usate
con l'eccezione.
- Usage-Guidance:
Testo in formato libero per dare suggerimenti agli utenti. Il testo deve
includere degli esempi su come usare gli identificatori di licenza SPDX
in un file sorgente in conformità con le linea guida in
`Sintassi degli identificatori di licenza`_.
- Exception-Text:
Tutto il testo che compare dopo questa etichetta viene trattato
come se fosse parte del testo originale della licenza.
Esempi::
SPDX-Exception-Identifier: Linux-syscall-note
SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
Usage-Guidance:
This exception is used together with one of the above SPDX-Licenses
to mark user-space API (uapi) header files so they can be included
into non GPL compliant user-space application code.
To use this exception add it with the keyword WITH to one of the
identifiers in the SPDX-Licenses tag:
SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
Exception-Text:
Full exception text
::
SPDX-Exception-Identifier: GCC-exception-2.0
SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html
SPDX-Licenses: GPL-2.0, GPL-2.0+
Usage-Guidance:
The "GCC Runtime Library exception 2.0" is used together with one
of the above SPDX-Licenses for code imported from the GCC runtime
library.
To use this exception add it with the keyword WITH to one of the
identifiers in the SPDX-Licenses tag:
SPDX-License-Identifier: <SPDX-License> WITH GCC-exception-2.0
Exception-Text:
Full exception text
Per ogni identificatore di licenza SPDX e per le eccezioni dev'esserci un file
nella sotto-cartella LICENSES. Questo è necessario per permettere agli
strumenti di effettuare verifiche (come checkpatch.pl), per avere le licenze
disponibili per la lettura e per estrarre i diritti dai sorgenti, così come
raccomandato da diverse organizzazioni FOSS, per esempio l'`iniziativa FSFE
REUSE <https://reuse.software/>`_.
_`MODULE_LICENSE`
-----------------
I moduli del kernel necessitano di un'etichetta MODULE_LICENSE(). Questa
etichetta non sostituisce le informazioni sulla licenza del codice sorgente
(SPDX-License-Identifier) né fornisce informazioni che esprimono o
determinano l'esatta licenza sotto la quale viene rilasciato.
Il solo scopo di questa etichetta è quello di fornire sufficienti
informazioni al caricatore di moduli del kernel, o agli strumenti in spazio
utente, per capire se il modulo è libero o proprietario.
Le stringe di licenza valide per MODULE_LICENSE() sono:
============================= =============================================
"GPL" Il modulo è licenziato con la GPL versione 2.
Questo non fa distinzione fra GPL'2.0-only o
GPL-2.0-or-later. L'esatta licenza può essere
determinata solo leggendo i corrispondenti
file sorgenti.
"GPL v2" Stesso significato di "GPL". Esiste per
motivi storici.
"GPL and additional rights" Questa è una variante che esiste per motivi
storici che indica che i sorgenti di un
modulo sono rilasciati sotto una variante
della licenza GPL v2 e quella MIT. Per favore
non utilizzatela per codice nuovo.
"Dual MIT/GPL" Questo è il modo corretto per esprimere il
il fatto che il modulo è rilasciato con
doppia licenza a scelta fra: una variante
della GPL v2 o la licenza MIT.
"Dual BSD/GPL" Questo modulo è rilasciato con doppia licenza
a scelta fra: una variante della GPL v2 o la
licenza BSD. La variante esatta della licenza
BSD può essere determinata solo attraverso i
corrispondenti file sorgenti.
"Dual MPL/GPL" Questo modulo è rilasciato con doppia licenza
a scelta fra: una variante della GPL v2 o la
Mozilla Public License (MPL). La variante
esatta della licenza MPL può essere
determinata solo attraverso i corrispondenti
file sorgenti.
"Proprietary" Questo modulo è rilasciato con licenza
proprietaria. Questa stringa è solo per i
moduli proprietari di terze parti e non può
essere usata per quelli che risiedono nei
sorgenti del kernel. I moduli etichettati in
questo modo stanno contaminando il kernel e
gli viene assegnato un flag 'P'; quando
vengono caricati, il caricatore di moduli del
kernel si rifiuterà di collegare questi
moduli ai simboli che sono stati esportati
con EXPORT_SYMBOL_GPL().
============================= =============================================
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/maintainer-pgp-guide.rst <pgpguide>`
:Translator: Alessia Mantegazza <amantegazza@vaga.pv.it>
.. _it_pgpguide:
=========================================
La guida a PGP per manutentori del kernel
=========================================
:Author: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
Questo documento è destinato agli sviluppatori del kernel Linux, in particolar
modo ai manutentori. Contiene degli approfondimenti riguardo informazioni che
sono state affrontate in maniera più generale nella sezione
"`Protecting Code Integrity`_" pubblicata dalla Linux Foundation.
Per approfondire alcuni argomenti trattati in questo documento è consigliato
leggere il documento sopraindicato
.. _`Protecting Code Integrity`: https://github.com/lfit/itpol/blob/master/protecting-code-integrity.md
Il ruolo di PGP nello sviluppo del kernel Linux
===============================================
PGP aiuta ad assicurare l'integrità del codice prodotto dalla comunità
di sviluppo del kernel e, in secondo luogo, stabilisce canali di comunicazione
affidabili tra sviluppatori attraverso lo scambio di email firmate con PGP.
Il codice sorgente del kernel Linux è disponibile principalmente in due
formati:
- repositori distribuiti di sorgenti (git)
- rilasci periodici di istantanee (archivi tar)
Sia i repositori git che gli archivi tar portano le firme PGP degli
sviluppatori che hanno creato i rilasci ufficiali del kernel. Queste firme
offrono una garanzia crittografica che le versioni scaricabili rese disponibili
via kernel.org, o altri portali, siano identiche a quelle che gli sviluppatori
hanno sul loro posto di lavoro. A tal scopo:
- i repositori git forniscono firme PGP per ogni tag
- gli archivi tar hanno firme separate per ogni archivio
.. _it_devs_not_infra:
Fidatevi degli sviluppatori e non dell'infrastruttura
-----------------------------------------------------
Fin dal 2011, quando i sistemi di kernel.org furono compromessi, il principio
generale del progetto Kernel Archives è stato quello di assumere che qualsiasi
parte dell'infrastruttura possa essere compromessa in ogni momento. Per questa
ragione, gli amministratori hanno intrapreso deliberatemene dei passi per
enfatizzare che la fiducia debba risiedere sempre negli sviluppatori e mai nel
codice che gestisce l'infrastruttura, indipendentemente da quali che siano le
pratiche di sicurezza messe in atto.
Il principio sopra indicato è la ragione per la quale è necessaria questa
guida. Vogliamo essere sicuri che il riporre la fiducia negli sviluppatori
non sia fatto semplicemente per incolpare qualcun'altro per future falle di
sicurezza. L'obiettivo è quello di fornire una serie di linee guida che gli
sviluppatori possano seguire per creare un ambiente di lavoro sicuro e
salvaguardare le chiavi PGP usate nello stabilire l'integrità del kernel Linux
stesso.
.. _it_pgp_tools:
Strumenti PGP
=============
Usare GnuPG v2
--------------
La vostra distribuzione potrebbe avere già installato GnuPG, dovete solo
verificare che stia utilizzando la versione 2.x e non la serie 1.4 --
molte distribuzioni forniscono entrambe, di base il comando ''gpg''
invoca GnuPG v.1. Per controllate usate::
$ gpg --version | head -n1
Se visualizzate ``gpg (GnuPG) 1.4.x``, allora state usando GnuPG v.1.
Provate il comando ``gpg2`` (se non lo avete, potreste aver bisogno
di installare il pacchetto gnupg2)::
$ gpg2 --version | head -n1
Se visualizzate ``gpg (GnuPG) 2.x.x``, allora siete pronti a partire.
Questa guida assume che abbiate la versione 2.2.(o successiva) di GnuPG.
Se state usando la versione 2.0, alcuni dei comandi indicati qui non
funzioneranno, in questo caso considerate un aggiornamento all'ultima versione,
la 2.2. Versioni di gnupg-2.1.11 e successive dovrebbero essere compatibili
per gli obiettivi di questa guida.
Se avete entrambi i comandi: ``gpg`` e ``gpg2``, assicuratevi di utilizzare
sempre la versione V2, e non quella vecchia. Per evitare errori potreste creare
un alias::
$ alias gpg=gpg2
Potete mettere questa opzione nel vostro ``.bashrc`` in modo da essere sicuri.
Configurare le opzioni di gpg-agent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
L'agente GnuPG è uno strumento di aiuto che partirà automaticamente ogni volta
che userete il comando ``gpg`` e funzionerà in background con l'obiettivo di
individuare la passphrase. Ci sono due opzioni che dovreste conoscere
per personalizzare la scadenza della passphrase nella cache:
- ``default-cache-ttl`` (secondi): Se usate ancora la stessa chiave prima
che il time-to-live termini, il conto alla rovescia si resetterà per un
altro periodo. Di base è di 600 (10 minuti).
- ``max-cache-ttl`` (secondi): indipendentemente da quanto sia recente l'ultimo
uso della chiave da quando avete inserito la passphrase, se il massimo
time-to-live è scaduto, dovrete reinserire nuovamente la passphrase.
Di base è di 30 minuti.
Se ritenete entrambe questi valori di base troppo corti (o troppo lunghi),
potete creare il vostro file ``~/.gnupg/gpg-agent.conf`` ed impostare i vostri
valori::
# set to 30 minutes for regular ttl, and 2 hours for max ttl
default-cache-ttl 1800
max-cache-ttl 7200
.. note::
Non è più necessario far partire l'agente gpg manualmente all'inizio della
vostra sessione. Dovreste controllare i file rc per rimuovere tutto ciò che
riguarda vecchie le versioni di GnuPG, poiché potrebbero non svolgere più
bene il loro compito.
Impostare un *refresh* con cronjob
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Potreste aver bisogno di rinfrescare regolarmente il vostro portachiavi in
modo aggiornare le chiavi pubbliche di altre persone, lavoro che è svolto
al meglio con un cronjob giornaliero::
@daily /usr/bin/gpg2 --refresh >/dev/null 2>&1
Controllate il percorso assoluto del vostro comando ``gpg`` o ``gpg2`` e usate
il comando ``gpg2`` se per voi ``gpg`` corrisponde alla versione GnuPG v.1.
.. _it_master_key:
Proteggere la vostra chiave PGP primaria
========================================
Guida a PGP per i manutentori del kernel
========================================
Questa guida parte dal presupposto che abbiate già una chiave PGP che usate
per lo sviluppo del kernel Linux. Se non ne avete ancora una, date uno sguardo
al documento "`Protecting Code Integrity`_" che abbiamo menzionato prima.
Dovreste inoltre creare una nuova chiave se quella attuale è inferiore a 2048
bit (RSA).
Chiave principale o sottochiavi
-------------------------------
Le sottochiavi sono chiavi PGP totalmente indipendenti, e sono collegate alla
chiave principale attraverso firme certificate. È quindi importante
comprendere i seguenti punti:
1. Non ci sono differenze tecniche tra la chiave principale e la sottochiave.
2. In fesa di creazione, assegniamo limitazioni funzionali ad ogni chiave
assegnando capacità specifiche.
3. Una chiave PGP può avere 4 capacità:
- **[S]** può essere usata per firmare
- **[E]** può essere usata per criptare
- **[A]** può essere usata per autenticare
- **[C]** può essere usata per certificare altre chiavi
4. Una singola chiave può avere più capacità
5. Una sottochiave è completamente indipendente dalla chiave principale.
Un messaggio criptato con la sottochiave non può essere decrittato con
quella principale. Se perdete la vostra sottochiave privata, non può
essere rigenerata in nessun modo da quella principale.
La chiave con capacità **[C]** (certify) è identificata come la chiave
principale perché è l'unica che può essere usata per indicare la relazione
con altre chiavi. Solo la chiave **[C]** può essere usata per:
- Aggiungere o revocare altre chiavi (sottochiavi) che hanno capacità S/E/A
- Aggiungere, modificare o eliminare le identità (unids) associate alla chiave
- Aggiungere o modificare la data di termine di sé stessa o di ogni sottochiave
- Firmare le chiavi di altre persone a scopo di creare una rete di fiducia
Di base, alla creazione di nuove chiavi, GnuPG genera quanto segue:
- Una chiave madre che porta sia la capacità di certificazione che quella
di firma (**[SC]**)
- Una sottochiave separata con capacità di criptaggio (**[E]**)
Se avete usato i parametri di base per generare la vostra chiave, quello
sarà il risultato. Potete verificarlo utilizzando ``gpg --list-secret-keys``,
per esempio::
sec rsa2048 2018-01-23 [SC] [expires: 2020-01-23]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23]
Qualsiasi chiave che abbia la capacità **[C]** è la vostra chiave madre,
indipendentemente da quali altre capacità potreste averle assegnato.
La lunga riga sotto la voce ``sec`` è la vostra impronta digitale --
negli esempi che seguono, quando vedere ``[fpr]`` ci si riferisce a questa
stringa di 40 caratteri.
Assicuratevi che la vostra passphrase sia forte
-----------------------------------------------
GnuPG utilizza le passphrases per criptare la vostra chiave privata prima
di salvarla sul disco. In questo modo, anche se il contenuto della vostra
cartella ``.gnupg`` venisse letto o trafugato nella sia interezza, gli
attaccanti non potrebbero comunque utilizzare le vostre chiavi private senza
aver prima ottenuto la passphrase per decriptarle.
È assolutamente essenziale che le vostre chiavi private siano protette da
una passphrase forte. Per impostarla o cambiarla, usate::
$ gpg --change-passphrase [fpr]
Create una sottochiave di firma separata
----------------------------------------
Il nostro obiettivo è di proteggere la chiave primaria spostandola su un
dispositivo sconnesso dalla rete, dunque se avete solo una chiave combinata
**[SC]** allora dovreste creare una sottochiave di firma separata::
$ gpg --quick-add-key [fpr] ed25519 sign
Ricordate di informare il keyserver del vostro cambiamento, cosicché altri
possano ricevere la vostra nuova sottochiave::
$ gpg --send-key [fpr]
.. note:: Supporto ECC in GnuPG
GnuPG 2.1 e successivi supportano pienamente *Elliptic Curve Cryptography*,
con la possibilità di combinare sottochiavi ECC con le tradizionali chiavi
primarie RSA. Il principale vantaggio della crittografia ECC è che è molto
più veloce da calcolare e crea firme più piccole se confrontate byte per
byte con le chiavi RSA a più di 2048 bit. A meno che non pensiate di
utilizzare un dispositivo smartcard che non supporta le operazioni ECC, vi
raccomandiamo ti creare sottochiavi di firma ECC per il vostro lavoro col
kernel.
Se per qualche ragione preferite rimanere con sottochiavi RSA, nel comando
precedente, sostituite "ed25519" con "rsa2048".
Copia di riserva della chiave primaria per gestire il recupero da disastro
--------------------------------------------------------------------------
Maggiori sono le firme di altri sviluppatori che vengono applicate alla vostra,
maggiori saranno i motivi per avere una copia di riserva che non sia digitale,
al fine di effettuare un recupero da disastro.
Il modo migliore per creare una copia fisica della vostra chiave privata è
l'uso del programma ``paperkey``. Consultate ``man paperkey`` per maggiori
dettagli sul formato dell'output ed i suoi punti di forza rispetto ad altre
soluzioni. Paperkey dovrebbe essere già pacchettizzato per la maggior parte
delle distribuzioni.
Eseguite il seguente comando per creare una copia fisica di riserva della
vostra chiave privata::
$ gpg --export-secret-key [fpr] | paperkey -o /tmp/key-backup.txt
Stampate il file (o fate un pipe direttamente verso lpr), poi prendete
una penna e scrivete la passphare sul margine del foglio. **Questo è
caldamente consigliato** perché la copia cartacea è comunque criptata con
la passphrase, e se mai doveste cambiarla non vi ricorderete qual'era al
momento della creazione di quella copia -- *garantito*.
Mettete la copia cartacea e la passphrase scritta a mano in una busta e
mettetela in un posto sicuro e ben protetto, preferibilmente fuori casa,
magari in una cassetta di sicurezza in banca.
.. note::
Probabilmente la vostra stampante non è più quello stupido dispositivo
connesso alla porta parallela, ma dato che il suo output è comunque
criptato con la passphrase, eseguire la stampa in un sistema "cloud"
moderno dovrebbe essere comunque relativamente sicuro. Un'opzione potrebbe
essere quella di cambiare la passphrase della vostra chiave primaria
subito dopo aver finito con paperkey.
Copia di riserva di tutta la cartella GnuPG
-------------------------------------------
.. warning::
TODO ancora da tradurre
**!!!Non saltate questo passo!!!**
Quando avete bisogno di recuperare le vostre chiavi PGP è importante avere
una copia di riserva pronta all'uso. Questo sta su un diverso piano di
prontezza rispetto al recupero da disastro che abbiamo risolto con
``paperkey``. Vi affiderete a queste copie esterne quando dovreste usare la
vostra chiave Certify -- ovvero quando fate modifiche alle vostre chiavi o
firmate le chiavi di altre persone ad una conferenza o ad un gruppo d'incontro.
Incominciate con una piccola chiavetta di memoria USB (preferibilmente due)
che userete per le copie di riserva. Dovrete criptarle usando LUKS -- fate
riferimento alla documentazione della vostra distribuzione per capire come
fare.
Per la passphrase di criptazione, potete usare la stessa della vostra chiave
primaria.
Una volta che il processo di criptazione è finito, reinserite il disco USB ed
assicurativi che venga montato correttamente. Copiate interamente la cartella
``.gnugp`` nel disco criptato::
$ cp -a ~/.gnupg /media/disk/foo/gnupg-backup
Ora dovreste verificare che tutto continui a funzionare::
$ gpg --homedir=/media/disk/foo/gnupg-backup --list-key [fpr]
Se non vedete errori, allora dovreste avere fatto tutto con successo.
Smontate il disco USB, etichettatelo per bene di modo da evitare di
distruggerne il contenuto non appena vi serve una chiavetta USB a caso, ed
infine mettetelo in un posto sicuro -- ma non troppo lontano, perché vi servirà
di tanto in tanto per modificare le identità, aggiungere o revocare
sottochiavi, o firmare le chiavi di altre persone.
Togliete la chiave primaria dalla vostra home
---------------------------------------------
I file che si trovano nella vostra cartella home non sono poi così ben protetti
come potreste pensare. Potrebbero essere letti o trafugati in diversi modi:
- accidentalmente quando fate una rapida copia della cartella home per
configurare una nuova postazione
- da un amministratore di sistema negligente o malintenzionato
- attraverso copie di riserva insicure
- attraverso malware installato in alcune applicazioni (browser, lettori PDF,
eccetera)
- attraverso coercizione quando attraversate confini internazionali
Proteggere la vostra chiave con una buona passphare aiuta notevolmente a
ridurre i rischi elencati qui sopra, ma le passphrase possono essere scoperte
attraverso i keylogger, il shoulder-surfing, o altri modi. Per questi motivi,
nella configurazione si raccomanda di rimuove la chiave primaria dalla vostra
cartella home e la si archivia su un dispositivo disconnesso.
.. warning::
Per favore, fate riferimento alla sezione precedente e assicuratevi
di aver fatto una copia di riserva totale della cartella GnuPG. Quello
che stiamo per fare renderà la vostra chiave inutile se non avete delle
copie di riserva utilizzabili!
Per prima cosa, identificate il keygrip della vostra chiave primaria::
$ gpg --with-keygrip --list-key [fpr]
L'output assomiglierà a questo::
pub rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
000000000000000000000000AAAABBBBCCCCDDDD
Keygrip = 1111000000000000000000000000000000000000
uid [ultimate] Alice Dev <adev@kernel.org>
sub rsa2048 2018-01-24 [E] [expires: 2020-01-24]
Keygrip = 2222000000000000000000000000000000000000
sub ed25519 2018-01-24 [S]
Keygrip = 3333000000000000000000000000000000000000
Trovate la voce keygrid che si trova sotto alla riga ``pub`` (appena sotto
all'impronta digitale della chiave primaria). Questo corrisponderà direttamente
ad un file nella cartella ``~/.gnupg``::
$ cd ~/.gnupg/private-keys-v1.d
$ ls
1111000000000000000000000000000000000000.key
2222000000000000000000000000000000000000.key
3333000000000000000000000000000000000000.key
Quello che dovrete fare è rimuovere il file .key che corrisponde al keygrip
della chiave primaria::
$ cd ~/.gnupg/private-keys-v1.d
$ rm 1111000000000000000000000000000000000000.key
Ora, se eseguite il comando ``--list-secret-keys``, vedrete che la chiave
primaria non compare più (il simbolo ``#`` indica che non è disponibile)::
$ gpg --list-secret-keys
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb rsa2048 2018-01-24 [E] [expires: 2020-01-24]
ssb ed25519 2018-01-24 [S]
Dovreste rimuovere anche i file ``secring.gpg`` che si trovano nella cartella
``~/.gnupg``, in quanto rimasugli delle versioni precedenti di GnuPG.
Se non avete la cartella "private-keys-v1.d"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Se non avete la cartella ``~/.gnupg/private-keys-v1.d``, allora le vostre
chiavi segrete sono ancora salvate nel vecchio file ``secring.gpg`` usato
da GnuPG v1. Effettuare una qualsiasi modifica alla vostra chiave, come
cambiare la passphare o aggiungere una sottochiave, dovrebbe convertire
automaticamente il vecchio formato ``secring.gpg``nel nuovo
``private-keys-v1.d``.
Una volta che l'avete fatto, assicuratevi di rimuovere il file ``secring.gpg``,
che continua a contenere la vostra chiave privata.
.. _it_smartcards:
Spostare le sottochiavi in un apposito dispositivo criptato
===========================================================
Nonostante la chiave primaria sia ora al riparo da occhi e mani indiscrete,
le sottochiavi si trovano ancora nella vostra cartella home. Chiunque riesca
a mettere le sue mani su quelle chiavi riuscirà a decriptare le vostre
comunicazioni o a falsificare le vostre firme (se conoscono la passphrase).
Inoltre, ogni volta che viene fatta un'operazione con GnuPG, le chiavi vengono
caricate nella memoria di sistema e potrebbero essere rubate con l'uso di
malware sofisticati (pensate a Meltdown e a Spectre).
Il miglior modo per proteggere le proprie chiave è di spostarle su un
dispositivo specializzato in grado di effettuare operazioni smartcard.
I benefici di una smartcard
---------------------------
Una smartcard contiene un chip crittografico che è capace di immagazzinare
le chiavi private ed effettuare operazioni crittografiche direttamente sulla
carta stessa. Dato che la chiave non lascia mai la smartcard, il sistema
operativo usato sul computer non sarà in grado di accedere alle chiavi.
Questo è molto diverso dai dischi USB criptati che abbiamo usato allo scopo di
avere una copia di riserva sicura -- quando il dispositivo USB è connesso e
montato, il sistema operativo potrà accedere al contenuto delle chiavi private.
L'uso di un disco USB criptato non può sostituire le funzioni di un dispositivo
capace di operazioni di tipo smartcard.
Dispositivi smartcard disponibili
---------------------------------
A meno che tutti i vostri computer dispongano di lettori smartcard, il modo
più semplice è equipaggiarsi di un dispositivo USB specializzato che
implementi le funzionalità delle smartcard. Sul mercato ci sono diverse
soluzioni disponibili:
- `Nitrokey Start`_: è Open hardware e Free Software, è basata sul progetto
`GnuK`_ della FSIJ. Ha il supporto per chiavi ECC, ma meno funzionalità di
sicurezza (come la resistenza alla manomissione o alcuni attacchi ad un
canale laterale).
- `Nitrokey Pro`_: è simile alla Nitrokey Start, ma è più resistente alla
manomissione e offre più funzionalità di sicurezza, ma l'ECC.
- `Yubikey 4`_: l'hardware e il software sono proprietari, ma è più economica
della Nitrokey Pro ed è venduta anche con porta USB-C il che è utile con i
computer portatili più recenti. In aggiunta, offre altre funzionalità di
sicurezza come FIDO, U2F, ma non l'ECC
`Su LWN c'è una buona recensione`_ dei modelli elencati qui sopra e altri.
Se volete usare chiavi ECC, la vostra migliore scelta sul mercato è la
Nitrokey Start.
.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6
.. _`Nitrokey Pro`: https://shop.nitrokey.com/shop/product/nitrokey-pro-3
.. _`Yubikey 4`: https://www.yubico.com/product/yubikey-4-series/
.. _Gnuk: http://www.fsij.org/doc-gnuk/
.. _`Su LWN c'è una buona recensione`: https://lwn.net/Articles/736231/
Configurare il vostro dispositivo smartcard
-------------------------------------------
Il vostro dispositivo smartcard dovrebbe iniziare a funzionare non appena
lo collegate ad un qualsiasi computer Linux moderno. Potete verificarlo
eseguendo::
$ gpg --card-status
Se vedete tutti i dettagli della smartcard, allora ci siamo. Sfortunatamente,
affrontare tutti i possibili motivi per cui le cose potrebbero non funzionare
non è lo scopo di questa guida. Se avete problemi nel far funzionare la carta
con GnuPG, cercate aiuto attraverso i soliti canali di supporto.
Per configurare la vostra smartcard, dato che non c'è una via facile dalla
riga di comando, dovrete usate il menu di GnuPG::
$ gpg --card-edit
[...omitted...]
gpg/card> admin
Admin commands are allowed
gpg/card> passwd
Dovreste impostare il PIN dell'utente (1), quello dell'amministratore (3) e il
codice di reset (4). Assicuratevi di annotare e salvare questi codici in un
posto sicuro -- specialmente il PIN dell'amministratore e il codice di reset
(che vi permetterà di azzerare completamente la smartcard). Il PIN
dell'amministratore viene usato così raramente che è inevitabile dimenticarselo
se non lo si annota.
Tornando al nostro menu, potete impostare anche altri valori (come il nome,
il sesso, informazioni d'accesso, eccetera), ma non sono necessari e aggiunge
altre informazioni sulla carta che potrebbero trapelare in caso di smarrimento.
.. note::
A dispetto del nome "PIN", né il PIN utente né quello dell'amministratore
devono essere esclusivamente numerici.
Spostare le sottochiavi sulla smartcard
---------------------------------------
Uscite dal menu (usando "q") e salverete tutte le modifiche. Poi, spostiamo
tutte le sottochiavi sulla smartcard. Per la maggior parte delle operazioni
vi serviranno sia la passphrase della chiave PGP che il PIN
dell'amministratore::
$ gpg --edit-key [fpr]
Secret subkeys are available.
pub rsa2048/AAAABBBBCCCCDDDD
created: 2018-01-23 expires: 2020-01-23 usage: SC
trust: ultimate validity: ultimate
ssb rsa2048/1111222233334444
created: 2018-01-23 expires: never usage: E
ssb ed25519/5555666677778888
created: 2017-12-07 expires: never usage: S
[ultimate] (1). Alice Dev <adev@kernel.org>
gpg>
Usando ``--edit-key`` si tornerà alla modalità menu e noterete che
la lista delle chiavi è leggermente diversa. Da questo momento in poi,
tutti i comandi saranno eseguiti nella modalità menu, come indicato
da ``gpg>``.
Per prima cosa, selezioniamo la chiave che verrà messa sulla carta --
potete farlo digitando ``key 1`` (è la prima della lista, la sottochiave
**[E]**)::
gpg> key 1
Nel'output dovreste vedere ``ssb*`` associato alla chiave **[E]**. Il simbolo
``*`` indica che la chiave è stata "selezionata". Funziona come un
interruttore, ovvero se scrivete nuovamente ``key 1``, il simbolo ``*`` sparirà
e la chiave non sarà più selezionata.
Ora, spostiamo la chiave sulla smartcard::
gpg> keytocard
Please select where to store the key:
(2) Encryption key
Your selection? 2
Dato che è la nostra chiave **[E]**, ha senso metterla nella sezione criptata.
Quando confermerete la selezione, vi verrà chiesta la passphrase della vostra
chiave PGP, e poi il PIN dell'amministratore. Se il comando ritorna senza
errori, allora la vostra chiave è stata spostata con successo.
**Importante**: digitate nuovamente ``key 1`` per deselezionare la prima chiave
e selezionate la seconda chiave **[S]** con ``key 2``::
gpg> key 1
gpg> key 2
gpg> keytocard
Please select where to store the key:
(1) Signature key
(3) Authentication key
Your selection? 1
Potete usare la chiave **[S]** sia per firmare che per autenticare, ma vogliamo
che sia nella sezione di firma, quindi scegliete (1). Ancora una volta, se il
comando ritorna senza errori, allora l'operazione è avvenuta con successo::
gpg> q
Save changes? (y/N) y
Salvando le modifiche cancellerete dalla vostra cartella home tutte le chiavi
che avete spostato sulla carta (ma questo non è un problema, perché abbiamo
fatto delle copie di sicurezza nel caso in cui dovessimo configurare una
nuova smartcard).
Verificare che le chiavi siano state spostate
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Ora, se doveste usare l'opzione ``--list-secret-keys``, vedrete una
sottile differenza nell'output::
$ gpg --list-secret-keys
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
000000000000000000000000AAAABBBBCCCCDDDD
uid [ultimate] Alice Dev <adev@kernel.org>
ssb> rsa2048 2018-01-24 [E] [expires: 2020-01-24]
ssb> ed25519 2018-01-24 [S]
Il simbolo ``>`` in ``ssb>`` indica che la sottochiave è disponibile solo
nella smartcard. Se tornate nella vostra cartella delle chiavi segrete e
guardate al suo contenuto, noterete che i file ``.key`` sono stati sostituiti
con degli stub::
$ cd ~/.gnupg/private-keys-v1.d
$ strings *.key | grep 'private-key'
Per indicare che i file sono solo degli stub e che in realtà il contenuto è
sulla smartcard, l'output dovrebbe mostrarvi ``shadowed-private-key``.
Verificare che la smartcard funzioni
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Per verificare che la smartcard funzioni come dovuto, potete creare
una firma::
$ echo "Hello world" | gpg --clearsign > /tmp/test.asc
$ gpg --verify /tmp/test.asc
Col primo comando dovrebbe chiedervi il PIN della smartcard, e poi dovrebbe
mostrare "Good signature" dopo l'esecuzione di ``gpg --verify``.
Complimenti, siete riusciti a rendere estremamente difficile il furto della
vostra identità digitale di sviluppatore.
Altre operazioni possibili con GnuPG
------------------------------------
Segue un breve accenno ad alcune delle operazioni più comuni che dovrete
fare con le vostre chiavi PGP.
Montare il disco con la chiave primaria
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Vi servirà la vostra chiave principale per tutte le operazioni che seguiranno,
per cui per prima cosa dovrete accedere ai vostri backup e dire a GnuPG di
usarli::
$ export GNUPGHOME=/media/disk/foo/gnupg-backup
$ gpg --list-secret-keys
Dovete assicurarvi di vedere ``sec`` e non ``sec#`` nell'output del programma
(il simbolo ``#`` significa che la chiave non è disponibile e che state ancora
utilizzando la vostra solita cartella di lavoro).
Estendere la data di scadenza di una chiave
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
La chiave principale ha una data di scadenza di 2 anni dal momento della sua
creazione. Questo per motivi di sicurezza e per rendere obsolete le chiavi
che, eventualmente, dovessero sparire dai keyserver.
Per estendere di un anno, dalla data odierna, la scadenza di una vostra chiave,
eseguite::
$ gpg --quick-set-expire [fpr] 1y
Se per voi è più facile da memorizzare, potete anche utilizzare una data
specifica (per esempio, il vostro compleanno o capodanno)::
$ gpg --quick-set-expire [fpr] 2020-07-01
Ricordatevi di inviare l'aggiornamento ai keyserver::
$ gpg --send-key [fpr]
Aggiornare la vostra cartella di lavoro dopo ogni modifica
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Dopo aver fatto delle modifiche alle vostre chiavi usando uno spazio a parte,
dovreste importarle nella vostra cartella di lavoro abituale::
$ gpg --export | gpg --homedir ~/.gnupg --import
$ unset GNUPGHOME
Usare PGP con Git
=================
Una delle caratteristiche fondanti di Git è la sua natura decentralizzata --
una volta che il repositorio è stato clonato sul vostro sistema, avete la
storia completa del progetto, inclusi i suoi tag, i commit ed i rami. Tuttavia,
con i centinaia di repositori clonati che ci sono in giro, come si fa a
verificare che la loro copia di linux.git non è stata manomessa da qualcuno?
Oppure, cosa succede se viene scoperta una backdoor nel codice e la riga
"Autore" dice che sei stato tu, mentre tu sei abbastanza sicuro di
`non averci niente a che fare`_?
Per risolvere entrambi i problemi, Git ha introdotto l'integrazione con PGP.
I tag firmati dimostrano che il repositorio è integro assicurando che il suo
contenuto è lo stesso che si trova sulle macchine degli sviluppatori che hanno
creato il tag; mentre i commit firmati rendono praticamente impossibile
ad un malintenzionato di impersonarvi senza avere accesso alle vostre chiavi
PGP.
.. _`non averci niente a che fare`: https://github.com/jayphelps/git-blame-someone-else
Configurare git per usare la vostra chiave PGP
----------------------------------------------
Se avete solo una chiave segreta nel vostro portachiavi, allora non avete nulla
da fare in più dato che sarà la vostra chiave di base. Tuttavia, se doveste
avere più chiavi segrete, potete dire a git quale dovrebbe usare (``[fpg]``
è la vostra impronta digitale)::
$ git config --global user.signingKey [fpr]
**IMPORTANTE**: se avete una comando dedicato per ``gpg2``, allora dovreste
dire a git di usare sempre quello piuttosto che il vecchio comando ``gpg``::
$ git config --global gpg.program gpg2
Come firmare i tag
------------------
Per creare un tag firmato, passate l'opzione ``-s`` al comando tag::
$ git tag -s [tagname]
La nostra raccomandazione è quella di firmare sempre i tag git, perché
questo permette agli altri sviluppatori di verificare che il repositorio
git dal quale stanno prendendo il codice non è stato alterato intenzionalmente.
Come verificare i tag firmati
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Per verificare un tag firmato, potete usare il comando ``verify-tag``::
$ git verify-tag [tagname]
Se state prendendo un tag da un fork del repositorio del progetto, git
dovrebbe verificare automaticamente la firma di quello che state prendendo
e vi mostrerà il risultato durante l'operazione di merge::
$ git pull [url] tags/sometag
Il merge conterrà qualcosa di simile::
Merge tag 'sometag' of [url]
[Tag message]
# gpg: Signature made [...]
# gpg: Good signature from [...]
Se state verificando il tag di qualcun altro, allora dovrete importare
la loro chiave PGP. Fate riferimento alla sezione ":ref:`it_verify_identities`"
che troverete più avanti.
Configurare git per firmare sempre i tag con annotazione
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Se state creando un tag con annotazione è molto probabile che vogliate
firmarlo. Per imporre a git di firmare sempre un tag con annotazione,
dovete impostare la seguente opzione globale::
$ git config --global tag.forceSignAnnotated true
Come usare commit firmati
-------------------------
Creare dei commit firmati è facile, ma è molto più difficile utilizzarli
nello sviluppo del kernel linux per via del fatto che ci si affida alle
liste di discussione e questo modo di procedere non mantiene le firme PGP
nei commit. In aggiunta, quando si usa *rebase* nel proprio repositorio
locale per allinearsi al kernel anche le proprie firme PGP verranno scartate.
Per questo motivo, la maggior parte degli sviluppatori del kernel non si
preoccupano troppo di firmare i propri commit ed ignoreranno quelli firmati
che si trovano in altri repositori usati per il proprio lavoro.
Tuttavia, se avete il vostro repositorio di lavoro disponibile al pubblico
su un qualche servizio di hosting git (kernel.org, infradead.org, ozlabs.org,
o altri), allora la raccomandazione è di firmare tutti i vostri commit
anche se gli sviluppatori non ne beneficeranno direttamente.
Vi raccomandiamo di farlo per i seguenti motivi:
1. Se dovesse mai esserci la necessità di fare delle analisi forensi o
tracciare la provenienza di un codice, anche sorgenti mantenuti
esternamente che hanno firme PGP sui commit avranno un certo valore a
questo scopo.
2. Se dovesse mai capitarvi di clonare il vostro repositorio locale (per
esempio dopo un danneggiamento del disco), la firma vi permetterà di
verificare l'integrità del repositorio prima di riprendere il lavoro.
3. Se qualcuno volesse usare *cherry-pick* sui vostri commit, allora la firma
permetterà di verificare l'integrità dei commit prima di applicarli.
Creare commit firmati
~~~~~~~~~~~~~~~~~~~~~
Per creare un commit firmato, dovete solamente aggiungere l'opzione ``-S``
al comando ``git commit`` (si usa la lettera maiuscola per evitare
conflitti con un'altra opzione)::
$ git commit -S
Configurare git per firmare sempre i commit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Potete dire a git di firmare sempre i commit::
git config --global commit.gpgSign true
.. note::
Assicuratevi di aver configurato ``gpg-agent`` prima di abilitare
questa opzione.
.. _it_verify_identities:
Come verificare l'identità degli sviluppatori del kernel
========================================================
Firmare i tag e i commit è facile, ma come si fa a verificare che la chiave
usata per firmare qualcosa appartenga davvero allo sviluppatore e non ad un
impostore?
Configurare l'auto-key-retrieval usando WKD e DANE
--------------------------------------------------
Se non siete ancora in possesso di una vasta collezione di chiavi pubbliche
di altri sviluppatori, allora potreste iniziare il vostro portachiavi
affidandovi ai servizi di auto-scoperta e auto-recupero. GnuPG può affidarsi
ad altre tecnologie di delega della fiducia, come DNSSEC e TLS, per sostenervi
nel caso in cui iniziare una propria rete di fiducia da zero sia troppo
scoraggiante.
Aggiungete il seguente testo al vostro file ``~/.gnupg/gpg.conf``::
auto-key-locate wkd,dane,local
auto-key-retrieve
La *DNS-Based Authentication of Named Entities* ("DANE") è un metodo
per la pubblicazione di chiavi pubbliche su DNS e per renderle sicure usando
zone firmate con DNSSEC. Il *Web Key Directory* ("WKD") è un metodo
alternativo che usa https a scopo di ricerca. Quando si usano DANE o WKD
per la ricerca di chiavi pubbliche, GnuPG validerà i certificati DNSSEC o TLS
prima di aggiungere al vostro portachiavi locale le eventuali chiavi trovate.
Kernel.org pubblica la WKD per tutti gli sviluppatori che hanno un account
kernel.org. Una volta che avete applicato le modifiche al file ``gpg.conf``,
potrete auto-recuperare le chiavi di Linus Torvalds e Greg Kroah-Hartman
(se non le avete già)::
$ gpg --locate-keys torvalds@kernel.org gregkh@kernel.org
Se avete un account kernel.org, al fine di rendere più utile l'uso di WKD
da parte di altri sviluppatori del kernel, dovreste `aggiungere alla vostra
chiave lo UID di kernel.org`_.
.. _`aggiungere alla vostra chiave lo UID di kernel.org`: https://korg.wiki.kernel.org/userdoc/mail#adding_a_kernelorg_uid_to_your_pgp_key
Web of Trust (WOT) o Trust on First Use (TOFU)
----------------------------------------------
PGP incorpora un meccanismo di delega della fiducia conosciuto come
"Web of Trust". Di base, questo è un tentativo di sostituire la necessità
di un'autorità certificativa centralizzata tipica del mondo HTTPS/TLS.
Invece di avere svariati produttori software che decidono chi dovrebbero
essere le entità di certificazione di cui dovreste fidarvi, PGP lascia
la responsabilità ad ogni singolo utente.
Sfortunatamente, solo poche persone capiscono come funziona la rete di fiducia.
Nonostante sia un importante aspetto della specifica OpenPGP, recentemente
le versioni di GnuPG (2.2 e successive) hanno implementato un meccanisco
alternativo chiamato "Trust on First Use" (TOFU). Potete pensare a TOFU come
"ad un approccio all fidicia simile ad SSH". In SSH, la prima volta che vi
connettete ad un sistema remoto, l'impronta digitale della chiave viene
registrata e ricordata. Se la chiave dovesse cambiare in futuro, il programma
SSH vi avviserà e si rifiuterà di connettersi, obbligandovi a prendere una
decisione circa la fiducia che riponete nella nuova chiave. In modo simile,
la prima volta che importate la chiave PGP di qualcuno, si assume sia valida.
Se ad un certo punto GnuPG trova un'altra chiave con la stessa identità,
entrambe, la vecchia e la nuova, verranno segnate come invalide e dovrete
verificare manualmente quale tenere.
Vi raccomandiamo di usare il meccanisco TOFU+PGP (che è la nuova configurazione
di base di GnuPG v2). Per farlo, aggiungete (o modificate) l'impostazione
``trust-model`` in ``~/.gnupg/gpg.conf``::
trust-model tofu+pgp
Come usare i keyserver in sicurezza
-----------------------------------
Se ottenete l'errore "No public key" quando cercate di validate il tag di
qualcuno, allora dovreste cercare quella chiave usando un keyserver. È
importante tenere bene a mente che non c'è alcuna garanzia che la chiave
che avete recuperato da un keyserver PGP appartenga davvero alla persona
reale -- è progettato così. Dovreste usare il Web of Trust per assicurarvi
che la chiave sia valida.
Come mantenere il Web of Trust va oltre gli scopi di questo documento,
semplicemente perché farlo come si deve richiede sia sforzi che perseveranza
che tendono ad andare oltre al livello di interesse della maggior parte degli
esseri umani. Qui di seguito alcuni rapidi suggerimenti per aiutarvi a ridurre
il rischio di importare chiavi maligne.
Primo, diciamo che avete provato ad eseguire ``git verify-tag`` ma restituisce
un errore dicendo che la chiave non è stata trovata::
$ git verify-tag sunxi-fixes-for-4.15-2
gpg: Signature made Sun 07 Jan 2018 10:51:55 PM EST
gpg: using RSA key DA73759BF8619E484E5A3B47389A54219C0F2430
gpg: issuer "wens@...org"
gpg: Can't check signature: No public key
Cerchiamo nel keyserver per maggiori informazioni sull'impronta digitale
della chiave (l'impronta digitale, probabilmente, appartiene ad una
sottochiave, dunque non possiamo usarla direttamente senza trovare prima
l'ID della chiave primaria associata ad essa)::
$ gpg --search DA73759BF8619E484E5A3B47389A54219C0F2430
gpg: data source: hkp://keys.gnupg.net
(1) Chen-Yu Tsai <wens@...org>
4096 bit RSA key C94035C21B4F2AEB, created: 2017-03-14, expires: 2019-03-15
Keys 1-1 of 1 for "DA73759BF8619E484E5A3B47389A54219C0F2430". Enter number(s), N)ext, or Q)uit > q
Localizzate l'ID della chiave primaria, nel nostro esempio
``C94035C21B4F2AEB``. Ora visualizzate le chiavi di Linus Torvalds
che avete nel vostro portachiavi::
$ gpg --list-key torvalds@kernel.org
pub rsa2048 2011-09-20 [SC]
ABAF11C65A2970B130ABE3C479BE3E4300411886
uid [ unknown] Linus Torvalds <torvalds@kernel.org>
sub rsa2048 2011-09-20 [E]
Poi, aprite il `PGP pathfinder`_. Nel campo "From", incollate l'impronta
digitale della chiave di Linus Torvalds che si vede nell'output qui sopra.
Nel campo "to", incollate il key-id della chiave sconosciuta che avete
trovato con ``gpg --search``, e poi verificare il risultato:
- `Finding paths to Linus`_
Se trovate un paio di percorsi affidabili è un buon segno circa la validità
della chiave. Ora, potete aggiungerla al vostro portachiavi dal keyserver::
$ gpg --recv-key C94035C21B4F2AEB
Questa procedura non è perfetta, e ovviamente state riponendo la vostra
fiducia nell'amministratore del servizio *PGP Pathfinder* sperando che non
sia malintenzionato (infatti, questo va contro :ref:`it_devs_not_infra`).
Tuttavia, se mantenete con cura la vostra rete di fiducia sarà un deciso
miglioramento rispetto alla cieca fiducia nei keyserver.
.. _`PGP pathfinder`: https://pgp.cs.uu.nl/
.. _`Finding paths to Linus`: https://pgp.cs.uu.nl/paths/79BE3E4300411886/to/C94035C21B4F2AEB.html
.. include:: ../disclaimer-ita.rst
:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
:Translator: Federico Vaga <federico.vaga@vaga.pv.it>
.. _it_stable_kernel_rules:
Tutto quello che volevate sapere sui rilasci -stable di Linux
==============================================================
.. warning::
Regole sul tipo di patch che vengono o non vengono accettate nei sorgenti
"-stable":
TODO ancora da tradurre
- Ovviamente dev'essere corretta e verificata.
- Non dev'essere più grande di 100 righe, incluso il contesto.
- Deve correggere una cosa sola.
- Deve correggere un baco vero che sta disturbando gli utenti (non cose del
tipo "Questo potrebbe essere un problema ...").
- Deve correggere un problema di compilazione (ma non per cose già segnate
con CONFIG_BROKEN), un kernel oops, un blocco, una corruzione di dati,
un vero problema di sicurezza, o problemi del tipo "oh, questo non va bene".
In pratica, qualcosa di critico.
- Problemi importanti riportati dagli utenti di una distribuzione potrebbero
essere considerati se correggono importanti problemi di prestazioni o di
interattività. Dato che questi problemi non sono così ovvi e la loro
correzione ha un'alta probabilità d'introdurre una regressione, dovrebbero
essere sottomessi solo dal manutentore della distribuzione includendo un
link, se esiste, ad un rapporto su bugzilla, e informazioni aggiuntive
sull'impatto che ha sugli utenti.
- Non deve correggere problemi relativi a una "teorica sezione critica",
a meno che non venga fornita anche una spiegazione su come questa si
possa verificare.
- Non deve includere alcuna correzione "banale" (correzioni grammaticali,
pulizia dagli spazi bianchi, eccetera).
- Deve rispettare le regole scritte in
:ref:`Documentation/translation/it_IT/process/submitting-patches.rst <it_submittingpatches>`
- Questa patch o una equivalente deve esistere già nei sorgenti principali di
Linux
Procedura per sottomettere patch per i sorgenti -stable
-------------------------------------------------------
- Se la patch contiene modifiche a dei file nelle cartelle net/ o drivers/net,
allora seguite le linee guida descritte in
:ref:`Documentation/translation/it_IT/networking/netdev-FAQ.rst <it_netdev-FAQ>`;
ma solo dopo aver verificato al seguente indirizzo che la patch non sia
già in coda:
https://patchwork.ozlabs.org/bundle/davem/stable/?series=&submitter=&state=*&q=&archive=
- Una patch di sicurezza non dovrebbero essere gestite (solamente) dal processo
di revisione -stable, ma dovrebbe seguire le procedure descritte in
:ref:`Documentation/translations/it_IT/admin-guide/security-bugs.rst <it_securitybugs>`.
Per tutte le altre sottomissioni, scegliere una delle seguenti procedure
------------------------------------------------------------------------
.. _it_option_1:
Opzione 1
*********
Per far sì che una patch venga automaticamente inclusa nei sorgenti stabili,
aggiungete l'etichetta
.. code-block:: none
Cc: stable@vger.kernel.org
nell'area dedicata alla firme. Una volta che la patch è stata inclusa, verrà
applicata anche sui sorgenti stabili senza che l'autore o il manutentore
del sottosistema debba fare qualcosa.
.. _it_option_2:
Opzione 2
*********
Dopo che la patch è stata inclusa nei sorgenti Linux, inviate una mail a
stable@vger.kernel.org includendo: il titolo della patch, l'identificativo
del commit, il perché pensate che debba essere applicata, e in quale versione
del kernel la vorreste vedere.
.. _it_option_3:
Opzione 3
*********
Inviata la patch, dopo aver verificato che rispetta le regole descritte in
precedenza, a stable@vger.kernel.org. Dovete annotare nel changelog
l'identificativo del commit nei sorgenti principali, così come la versione
del kernel nel quale vorreste vedere la patch.
L':ref:`it_option_1` è fortemente raccomandata; è il modo più facile e usato.
L':ref:`it_option_2` e l':ref:`it_option_3` sono più utili quando, al momento
dell'inclusione dei sorgenti principali, si ritiene che non debbano essere
incluse anche in quelli stabili (per esempio, perché si crede che si dovrebbero
fare più verifiche per eventuali regressioni). L':ref:`it_option_3` è
particolarmente utile se la patch ha bisogno di qualche modifica per essere
applicata ad un kernel più vecchio (per esempio, perché nel frattempo l'API è
cambiata).
Notate che per l':ref:`it_option_3`, se la patch è diversa da quella nei
sorgenti principali (per esempio perché è stato necessario un lavoro di
adattamento) allora dev'essere ben documentata e giustificata nella descrizione
della patch.
L'identificativo del commit nei sorgenti principali dev'essere indicato sopra
al messaggio della patch, così:
.. code-block:: none
commit <sha1> upstream.
In aggiunta, alcune patch inviate attraverso l':ref:`it_option_1` potrebbero
dipendere da altre che devo essere incluse. Questa situazione può essere
indicata nel seguente modo nell'area dedicata alle firme:
.. code-block:: none
Cc: <stable@vger.kernel.org> # 3.3.x: a1f84a3: sched: Check for idle
Cc: <stable@vger.kernel.org> # 3.3.x: 1b9508f: sched: Rate-limit newidle
Cc: <stable@vger.kernel.org> # 3.3.x: fd21073: sched: Fix affinity logic
Cc: <stable@vger.kernel.org> # 3.3.x
Signed-off-by: Ingo Molnar <mingo@elte.hu>
La sequenza di etichette ha il seguente significato:
.. code-block:: none
git cherry-pick a1f84a3
git cherry-pick 1b9508f
git cherry-pick fd21073
git cherry-pick <this commit>
Inoltre, alcune patch potrebbero avere dei requisiti circa la versione del
kernel. Questo può essere indicato usando il seguente formato nell'area
dedicata alle firme:
.. code-block:: none
Cc: <stable@vger.kernel.org> # 3.3.x
L'etichetta ha il seguente significato:
.. code-block:: none
git cherry-pick <this commit>
per ogni sorgente "-stable" che inizia con la versione indicata.
Dopo la sottomissione:
- Il mittente riceverà un ACK quando la patch è stata accettata e messa in
coda, oppure un NAK se la patch è stata rigettata. A seconda degli impegni
degli sviluppatori, questa risposta potrebbe richiedere alcuni giorni.
- Se accettata, la patch verrà aggiunta alla coda -stable per essere
revisionata dal altri sviluppatori e dal principale manutentore del
sottosistema.
Ciclo di una revisione
----------------------
- Quando i manutentori -stable decidono di fare un ciclo di revisione, le
patch vengono mandate al comitato per la revisione, ai manutentori soggetti
alle modifiche delle patch (a meno che il mittente non sia anche il
manutentore di quell'area del kernel) e in CC: alla lista di discussione
linux-kernel.
- La commissione per la revisione ha 48 ore per dare il proprio ACK o NACK
alle patch.
- Se una patch viene rigettata da un membro della commissione, o un membro
della lista linux-kernel obietta la bontà della patch, sollevando problemi
che i manutentori ed i membri non avevano compreso, allora la patch verrà
rimossa dalla coda.
- Alla fine del ciclo di revisione tutte le patch che hanno ricevuto l'ACK
verranno aggiunte per il prossimo rilascio -stable, e successivamente
questo nuovo rilascio verrà fatto.
- Le patch di sicurezza verranno accettate nei sorgenti -stable direttamente
dalla squadra per la sicurezza del kernel, e non passerà per il normale
ciclo di revisione. Contattate la suddetta squadra per maggiori dettagli
su questa procedura.
Sorgenti
--------
- La coda delle patch, sia quelle già applicate che in fase di revisione,
possono essere trovate al seguente indirizzo:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/stable-queue.git
- Il rilascio definitivo, e marchiato, di tutti i kernel stabili può essere
trovato in rami distinti per versione al seguente indirizzo:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
Comitato per la revisione
-------------------------
- Questo comitato è fatto di sviluppatori del kernel che si sono offerti
volontari per questo lavoro, e pochi altri che non sono proprio volontari.
......@@ -67,8 +67,8 @@ sulla radice dei sorgenti del kernel, e non sulle sue sottocartelle.
Per creare una patch per un singolo file, spesso è sufficiente fare::
SRCTREE= linux
MYFILE= drivers/net/mydriver.c
SRCTREE=linux
MYFILE=drivers/net/mydriver.c
cd $SRCTREE
cp $MYFILE $MYFILE.orig
......@@ -80,7 +80,7 @@ Per creare una patch per molteplici file, dovreste spacchettare i sorgenti
"vergini", o comunque non modificati, e fare un ``diff`` coi vostri.
Per esempio::
MYSRC= /devel/linux
MYSRC=/devel/linux
tar xvfz linux-3.19.tar.gz
mv linux-3.19 linux-3.19-vanilla
......@@ -567,11 +567,42 @@ alcunché - ma dovrebbe indicare che la persona ha ricevuto una copia della
patch. Questa etichetta documenta che terzi potenzialmente interessati sono
stati inclusi nella discussione.
L'etichetta Co-developed-by: indica che la patch è stata scritta dall'autore in
collaborazione con un altro sviluppatore. Qualche volta questo è utile quando
più persone lavorano sulla stessa patch. Notate, questa persona deve avere
nella patch anche una riga Signed-off-by:.
Co-developed-by: indica che la patch è stata cosviluppata da diversi
sviluppatori; viene usato per assegnare più autori (in aggiunta a quello
associato all'etichetta From:) quando più persone lavorano ad una patch. Dato
che Co-developed-by: implica la paternità della patch, ogni Co-developed-by:
dev'essere seguito immediatamente dal Signed-off-by: del corrispondente
coautore. Qui si applica la procedura di base per sign-off, in pratica
l'ordine delle etichette Signed-off-by: dovrebbe riflettere il più possibile
l'ordine cronologico della storia della patch, indipendentemente dal fatto che
la paternità venga assegnata via From: o Co-developed-by:. Da notare che
l'ultimo Signed-off-by: dev'essere quello di colui che ha sottomesso la patch.
Notate anche che l'etichetta From: è opzionale quando l'autore in From: è
anche la persona (e indirizzo email) indicato nel From: dell'intestazione
dell'email.
Esempio di una patch sottomessa dall'autore in From:::
<changelog>
Co-developed-by: First Co-Author <first@coauthor.example.org>
Signed-off-by: First Co-Author <first@coauthor.example.org>
Co-developed-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Esempio di una patch sottomessa dall'autore Co-developed-by:::
From: From Author <from@author.example.org>
<changelog>
Co-developed-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
13) Utilizzare Reported-by:, Tested-by:, Reviewed-by:, Suggested-by: e Fixes:
-----------------------------------------------------------------------------
......@@ -719,7 +750,7 @@ Un paio di esempi di oggetti::
La riga ``from`` dev'essere la prima nel corpo del messaggio ed è nel
formato:
From: Original Author <author@example.com>
From: Patch Author <author@example.com>
La riga ``from`` indica chi verrà accreditato nel changelog permanente come
l'autore della patch. Se la riga ``from`` è mancante, allora per determinare
......
......@@ -58,8 +58,8 @@ Linux カーネルに対する全ての変更は diff(1) コマンドによる
1個のファイルについてのパッチを作成するためには、ほとんどの場合、
以下の作業を行えば十分です。
SRCTREE= linux-2.6
MYFILE= drivers/net/mydriver.c
SRCTREE=linux-2.6
MYFILE=drivers/net/mydriver.c
cd $SRCTREE
cp $MYFILE $MYFILE.orig
......@@ -71,7 +71,7 @@ Linux カーネルに対する全ての変更は diff(1) コマンドによる
なわち変更を加えてない Linux カーネルを展開し、自分の Linux カーネル
ソースとの差分を生成しないといけません。例えば、
MYSRC= /devel/linux-2.6
MYSRC=/devel/linux-2.6
tar xvfz linux-2.6.12.tar.gz
mv linux-2.6.12 linux-2.6.12-vanilla
......
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>
--
:orphan:
.. warning::
此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此,
如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。
.. note::
如果您发现本文档与原始文件有任何不同或者有翻译问题,请联系该文件的译者,
或者请求时奎亮的帮助:<alex.shi@linux.alibaba.com>。
......@@ -3,10 +3,19 @@
\renewcommand\thesection*
\renewcommand\thesubsection*
Chinese translations
====================
中文翻译
========
这些手册包含有关如何开发内核的整体信息。内核社区非常庞大,一年下来有数千名开发
人员做出贡献。 与任何大型社区一样,知道如何完成任务将使得更改合并的过程变得更
加容易。
.. toctree::
:maxdepth: 1
:maxdepth: 2
process/index
目录和表格
----------
coding-style
* :ref:`genindex`
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中找到他们。
......@@ -16,7 +16,7 @@ Documentation/admin-guide/bug-hunting.rst 的中文翻译
中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
......
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/1.Intro.rst <development_process_intro>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_process_intro:
介绍
====
执行摘要
--------
本节的其余部分涵盖了内核开发过程的范围,以及开发人员及其雇主在这方面可能遇
到的各种挫折。内核代码应该合并到正式的(“主线”)内核中有很多原因,包括对用
户的自动可用性、多种形式的社区支持以及影响内核开发方向的能力。提供给Linux
内核的代码必须在与GPL兼容的许可证下可用。
:ref:`cn_development_process` 介绍了开发过程、内核发布周期和合并窗口的机制。
涵盖了补丁开发、审查和合并周期中的各个阶段。有一些关于工具和邮件列表的讨论。
鼓励希望开始内核开发的开发人员作为初始练习跟踪并修复bug。
:ref:`cn_development_early_stage` 包括早期项目规划,重点是尽快让开发社区参与
:ref:`cn_development_coding` 是关于编码过程的;讨论了其他开发人员遇到的几个
陷阱。对补丁的一些要求已经涵盖,并且介绍了一些工具,这些工具有助于确保内核
补丁是正确的。
:ref:`cn_development_posting` 讨论发布补丁以供评审的过程。为了让开发社区
认真对待,补丁必须正确格式化和描述,并且必须发送到正确的地方。遵循本节中的
建议有助于确保为您的工作提供最好的接纳。
:ref:`cn_development_followthrough` 介绍了发布补丁之后发生的事情;该工作
在这一点上还远远没有完成。与审阅者一起工作是开发过程中的一个重要部分;本节
提供了一些关于如何在这个重要阶段避免问题的提示。当补丁被合并到主线中时,
开发人员要注意不要假定任务已经完成。
:ref:`cn_development_advancedtopics` 介绍了两个“高级”主题:
使用Git管理补丁和查看其他人发布的补丁。
:ref:`cn_development_conclusion` 总结了有关内核开发的更多信息,附带有带有
指向资源的链接.
这个文件是关于什么的
--------------------
Linux内核有超过800万行代码,每个版本的贡献者超过1000人,是现存最大、最活跃
的免费软件项目之一。从1991年开始,这个内核已经发展成为一个最好的操作系统
组件,运行在袖珍数字音乐播放器、台式PC、现存最大的超级计算机以及所有类型的
系统上。它是一种适用于几乎任何情况的健壮、高效和可扩展的解决方案。
随着Linux的发展,希望参与其开发的开发人员(和公司)的数量也在增加。硬件供应商
希望确保Linux能够很好地支持他们的产品,使这些产品对Linux用户具有吸引力。嵌入
式系统供应商使用Linux作为集成产品的组件,希望Linux能够尽可能地胜任手头的任务。
分销商和其他基于Linux的软件供应商对Linux内核的功能、性能和可靠性有着明确的
兴趣。最终用户也常常希望修改Linux,使之更好地满足他们的需求。
Linux最引人注目的特性之一是这些开发人员可以访问它;任何具备必要技能的人都可以
改进Linux并影响其开发方向。专有产品不能提供这种开放性,这是自由软件的一个特点。
但是,如果有什么不同的话,内核比大多数其他自由软件项目更开放。一个典型的三个月
内核开发周期可以涉及1000多个开发人员,他们为100多个不同的公司
(或者根本没有公司)工作。
与内核开发社区合作并不是特别困难。但是,尽管如此,许多潜在的贡献者在尝试做
内核工作时遇到了困难。内核社区已经发展了自己独特的操作方式,使其能够在每天
都要更改数千行代码的环境中顺利运行(并生成高质量的产品)。因此,Linux内核开发
过程与专有的开发方法有很大的不同也就不足为奇了。
对于新开发人员来说,内核的开发过程可能会让人感到奇怪和恐惧,但这个背后有充分的
理由和坚实的经验。一个不了解内核社区的方式的开发人员(或者更糟的是,他们试图
抛弃或规避内核社区的方式)会有一个令人沮丧的体验。开发社区, 在帮助那些试图学习
的人的同时,没有时间帮助那些不愿意倾听或不关心开发过程的人。
希望阅读本文的人能够避免这种令人沮丧的经历。这里有很多材料,但阅读时所做的
努力会在短时间内得到回报。开发社区总是需要能让内核变更好的开发人员;下面的
文本应该帮助您或为您工作的人员加入我们的社区。
致谢
----
本文件由Jonathan Corbet撰写,corbet@lwn.net。以下人员的建议使之更为完善:
Johannes Berg, James Berry, Alex Chiang, Roland Dreier, Randy Dunlap,
Jake Edge, Jiri Kosina, Matt Mackall, Arthur Marsh, Amanda McPherson,
Andrew Morton, Andrew Price, Tsugikazu Shibata, 和 Jochen Voß.
这项工作得到了Linux基金会的支持,特别感谢Amanda McPherson,他看到了这项工作
的价值并把它变成现实。
代码进入主线的重要性
--------------------
有些公司和开发人员偶尔会想,为什么他们要费心学习如何与内核社区合作,并将代码
放入主线内核(“主线”是由Linus Torvalds维护的内核,Linux发行商将其用作基础)。
在短期内,贡献代码看起来像是一种可以避免的开销;仅仅将代码分开并直接支持用户
似乎更容易。事实上,保持代码独立(“树外”)是在经济上是错误的。
作为说明树外代码成本的一种方法,下面是内核开发过程的一些相关方面;本文稍后将
更详细地讨论其中的大部分内容。考虑:
- 所有Linux用户都可以使用合并到主线内核中的代码。它将自动出现在所有启用它的
发行版上。不需要驱动程序磁盘、下载,也不需要为多个发行版的多个版本提供支持;
对于开发人员和用户来说,这一切都是可行的。并入主线解决了大量的分布和支持问题
- 当内核开发人员努力维护一个稳定的用户空间接口时,内部内核API处于不断变化之中.
缺乏一个稳定的内部接口是一个深思熟虑的设计决策;它允许在任何时候进行基本的改
进,并产生更高质量的代码。但该策略的一个结果是,如果要使用新的内核,任何树外
代码都需要持续的维护。维护树外代码需要大量的工作才能使代码保持工作状态。
相反,位于主线中的代码不需要这样做,因为一个简单的规则要求进行API更改的任何
开发人员也必须修复由于该更改而破坏的任何代码。因此,合并到主线中的代码大大
降低了维护成本。
- 除此之外,内核中的代码通常会被其他开发人员改进。令人惊讶的结果可能来自授权
您的用户社区和客户改进您的产品。
- 内核代码在合并到主线之前和之后都要经过审查。不管原始开发人员的技能有多强,
这个审查过程总是能找到改进代码的方法。审查经常发现严重的错误和安全问题。
这对于在封闭环境中开发的代码尤其如此;这种代码从外部开发人员的审查中获益
匪浅。树外代码是低质量代码。
- 参与开发过程是您影响内核开发方向的方式。旁观者的抱怨会被听到,但是活跃的
开发人员有更强的声音——并且能够实现使内核更好地满足其需求的更改。
- 当单独维护代码时,总是存在第三方为类似功能提供不同实现的可能性。如果发生
这种情况,合并代码将变得更加困难——甚至到了不可能的地步。然后,您将面临以下
令人不快的选择:(1)无限期地维护树外的非标准特性,或(2)放弃代码并将用户
迁移到树内版本。
- 代码的贡献是使整个过程工作的根本。通过贡献代码,您可以向内核添加新功能,并
提供其他内核开发人员使用的功能和示例。如果您已经为Linux开发了代码(或者
正在考虑这样做),那么您显然对这个平台的持续成功感兴趣;贡献代码是确保成功
的最好方法之一。
上述所有理由都适用于任何树外内核代码,包括以专有的、仅二进制形式分发的代码。
然而,在考虑任何类型的纯二进制内核代码分布之前,还需要考虑其他因素。这些包括:
- 围绕专有内核模块分发的法律问题充其量是模糊的;相当多的内核版权所有者认为,
大多数仅限二进制的模块是内核的派生产品,因此,它们的分发违反了GNU通用公共
许可证(下面将详细介绍)。您的作者不是律师,本文档中的任何内容都不可能被
视为法律建议。封闭源代码模块的真实法律地位只能由法院决定。但不管怎样,困扰
这些模块的不确定性仍然存在。
- 二进制模块大大增加了调试内核问题的难度,以至于大多数内核开发人员甚至都不会
尝试。因此,只分发二进制模块将使您的用户更难从社区获得支持。
- 对于只支持二进制的模块的发行者来说,支持也更加困难,他们必须为他们希望支持
的每个发行版和每个内核版本提供一个版本的模块。为了提供相当全面的覆盖范围,
可能需要一个模块的几十个构建,并且每次升级内核时,您的用户都必须单独升级
您的模块。
- 上面提到的关于代码评审的所有问题都更加存在于封闭源代码。由于该代码根本不可
用,因此社区无法对其进行审查,毫无疑问,它将存在严重问题。
尤其是嵌入式系统的制造商,可能会倾向于忽视本节中所说的大部分内容,因为他们
相信自己正在商用一种使用冻结内核版本的独立产品,在发布后不需要再进行开发。
这个论点忽略了广泛的代码审查的价值以及允许用户向产品添加功能的价值。但这些
产品也有有限的商业寿命,之后必须发布新版本的产品。在这一点上,代码在主线上
并得到良好维护的供应商将能够更好地占位,以使新产品快速上市。
许可
----
代码是根据一些许可证提供给Linux内核的,但是所有代码都必须与GNU通用公共许可
证(GPLV2)的版本2兼容,该版本是覆盖整个内核分发的许可证。在实践中,这意味
着所有代码贡献都由GPLv2(可选地,语言允许在更高版本的GPL下分发)或3子句BSD
许可(New BSD License, 译者注)覆盖。任何不包含在兼容许可证中的贡献都不会
被接受到内核中。
贡献给内核的代码不需要(或请求)版权分配。合并到主线内核中的所有代码都保留
其原始所有权;因此,内核现在拥有数千个所有者。
这种所有权结构的一个暗示是,任何改变内核许可的尝试都注定会失败。很少有实际
的场景可以获得所有版权所有者的同意(或者从内核中删除他们的代码)。因此,特
别是,在可预见的将来,不可能迁移到GPL的版本3。
所有贡献给内核的代码都必须是合法的免费软件。因此,不接受匿名(或匿名)贡献
者的代码。所有贡献者都需要在他们的代码上“sign off”,声明代码可以在GPL下与内
核一起分发。无法提供未被其所有者许可为免费软件的代码,或可能为内核造成版权
相关问题的代码(例如,由缺乏适当保护的反向工程工作派生的代码)不能被接受。
有关版权相关问题的问题在Linux开发邮件列表中很常见。这样的问题通常会得到不少
答案,但要记住,回答这些问题的人不是律师,不能提供法律咨询。如果您有关于
Linux源代码的法律问题,那么与了解该领域的律师交流是无法替代的。依靠从技术
邮件列表中获得的答案是一件冒险的事情。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/2.Process.rst <development_process>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_process:
开发流程如何工作
================
90年代早期的Linux内核开发是一件相当松散的事情,涉及的用户和开发人员相对较
少。由于拥有数以百万计的用户群,并且在一年的时间里有大约2000名开发人员参与
进来,内核因此必须发展许多流程来保持开发的顺利进行。要成为流程的有效组成
部分,需要对流程的工作方式有一个扎实的理解。
总览
----
内核开发人员使用一个松散的基于时间的发布过程,每两到三个月发布一次新的主要
内核版本。最近的发布历史记录如下:
====== =================
4.11 四月 30, 2017
4.12 七月 2, 2017
4.13 九月 3, 2017
4.14 十一月 12, 2017
4.15 一月 28, 2018
4.16 四月 1, 2018
====== =================
每4.x版本都是一个主要的内核版本,具有新特性、内部API更改等等。一个典型的4.x
版本包含大约13000个变更集,变更了几十万行代码。因此,4.x是Linux内核开发的前
沿;内核使用滚动开发模型,不断集成重大变化。
对于每个版本的补丁合并,遵循一个相对简单的规则。在每个开发周期的开始,“合并
窗口”被打开。当时,被认为足够稳定(并且被开发社区接受)的代码被合并到主线内
核中。在这段时间内,新开发周期的大部分变更(以及所有主要变更)将以接近每天
1000次变更(“补丁”或“变更集”)的速度合并。
(顺便说一句,值得注意的是,合并窗口期间集成的更改并不是凭空产生的;它们是
提前收集、测试和分级的。稍后将详细描述该过程的工作方式)。
合并窗口持续大约两周。在这段时间结束时,LinusTorvalds将声明窗口已关闭,并
释放第一个“rc”内核。例如,对于目标为4.14的内核,在合并窗口结束时发生的释放
将被称为4.14-rc1。RC1版本是一个信号,表示合并新特性的时间已经过去,稳定下一
个内核的时间已经开始。
在接下来的6到10周内,只有修复问题的补丁才应该提交给主线。有时会允许更大的
更改,但这种情况很少发生;试图在合并窗口外合并新功能的开发人员往往会受到不
友好的接待。一般来说,如果您错过了给定特性的合并窗口,最好的做法是等待下一
个开发周期。(对于以前不支持的硬件,偶尔会对驱动程序进行例外;如果它们不
改变已有代码,则不会导致回归,并且应该可以随时安全地添加)。
随着修复程序进入主线,补丁速度将随着时间的推移而变慢。Linus大约每周发布一次
新的-rc内核;一个正常的系列将在-rc6和-rc9之间,内核被认为足够稳定并最终发布。
然后,整个过程又重新开始了。
例如,这里是4.16的开发周期进行情况(2018年的所有日期):
============== ==============================
一月 28 4.15 稳定版发布
二月 11 4.16-rc1, 合并窗口关闭
二月 18 4.16-rc2
二月 25 4.16-rc3
三月 4 4.16-rc4
三月 11 4.16-rc5
三月 18 4.16-rc6
三月 25 4.16-rc7
四月 1 4.16 稳定版发布
============== ==============================
开发人员如何决定何时结束开发周期并创建稳定的版本?使用的最重要的指标是以前
版本的回归列表。不欢迎出现任何错误,但是那些破坏了以前能工作的系统的错误被
认为是特别严重的。因此,导致回归的补丁是不受欢迎的,很可能在稳定期内删除。
开发人员的目标是在稳定发布之前修复所有已知的回归。在现实世界中,这种完美是
很难实现的;在这种规模的项目中,变量太多了。有一点,延迟最终版本只会使问题
变得更糟;等待下一个合并窗口的一堆更改将变大,从而在下次创建更多的回归错误。
因此,大多数4.x内核都有一些已知的回归错误,不过,希望没有一个是严重的。
一旦一个稳定的版本发布,它正在进行的维护工作就被移交给“稳定团队”,目前由
Greg Kroah-Hartman组成。稳定团队将使用4.x.y编号方案不定期的发布稳定版本的更
新。要加入更新版本,补丁程序必须(1)修复一个重要的bug,(2)已经合并到
下一个开发主线中。内核通常会在超过其初始版本的一个以上的开发周期内接收稳定
的更新。例如,4.13内核的历史如下
============== ===============================
九月 3 4.13 稳定版发布
九月 13 4.13.1
九月 20 4.13.2
九月 27 4.13.3
十月 5 4.13.4
十月 12 4.13.5
... ...
十一月 24 4.13.16
============== ===============================
4.13.16是4.13版本的最终稳定更新。
有些内核被指定为“长期”内核;它们将得到更长时间的支持。在本文中,当前的长期
内核及其维护者是:
====== ====================== ==============================
3.16 Ben Hutchings (长期稳定内核)
4.1 Sasha Levin
4.4 Greg Kroah-Hartman (长期稳定内核)
4.9 Greg Kroah-Hartman
4.14 Greg Kroah-Hartman
====== ====================== ==============================
为长期支持选择内核纯粹是维护人员有必要和时间来维护该版本的问题。目前还没有
为即将发布的任何特定版本提供长期支持的已知计划。
补丁的生命周期
--------------
补丁不会直接从开发人员的键盘进入主线内核。相反,有一个稍微复杂(如果有些非
正式)的过程,旨在确保对每个补丁进行质量审查,并确保每个补丁实现了一个在主线
中需要的更改。对于小的修复,这个过程可能会很快发生,或者,在大的和有争议的
变更的情况下,会持续数年。许多开发人员的挫折来自于对这个过程缺乏理解或者
试图绕过它。
为了减少这种挫折感,本文将描述补丁如何进入内核。下面是一个介绍,它以某种
理想化的方式描述了这个过程。更详细的过程将在后面的章节中介绍。
补丁程序经历的阶段通常是:
- 设计。这就是补丁的真正需求——以及满足这些需求的方式——的所在。设计工作通常
是在不涉及社区的情况下完成的,但是如果可能的话,最好是在公开的情况下完成
这项工作;这样可以节省很多稍后再重新设计的时间。
- 早期评审。补丁被发布到相关的邮件列表中,列表中的开发人员会回复他们可能有
的任何评论。如果一切顺利的话,这个过程应该会发现补丁的任何主要问题。
- 更广泛的评审。当补丁接近准备好纳入主线时,它应该被相关的子系统维护人员
接受——尽管这种接受并不能保证补丁会一直延伸到主线。补丁将出现在维护人员的
子系统树中,并进入 -next 树(如下所述)。当流程工作时,此步骤将导致对补丁
进行更广泛的审查,并发现由于将此补丁与其他人所做的工作集成而导致的任何
问题。
- 请注意,大多数维护人员也有日常工作,因此合并补丁可能不是他们的最高优先级。
如果您的补丁程序得到了关于所需更改的反馈,那么您应该进行这些更改,或者为
不应该进行这些更改的原因辩护。如果您的补丁没有评审意见,但没有被其相应的
子系统或驱动程序维护者接受,那么您应该坚持不懈地将补丁更新到当前内核,使
其干净地应用,并不断地将其发送以供审查和合并。
- 合并到主线。最终,一个成功的补丁将被合并到由LinusTorvalds管理的主线存储库
中。此时可能会出现更多的评论和/或问题;开发人员应对这些问题并解决出现的
任何问题很重要。
- 稳定版发布。可能受补丁影响的用户数量现在很大,因此可能再次出现新的问题。
- 长期维护。虽然开发人员在合并代码后可能会忘记代码,但这种行为往往会给开发
社区留下不良印象。合并代码消除了一些维护负担,因为其他代码将修复由API
更改引起的问题。但是,如果代码要长期保持有用,原始开发人员应该继续为
代码负责。
内核开发人员(或他们的雇主)犯的最大错误之一是试图将流程简化为一个
“合并到主线”步骤。这种方法总是会让所有相关人员感到沮丧。
补丁如何进入内核
----------------
只有一个人可以将补丁合并到主线内核存储库中:LinusTorvalds。但是,在进入
2.6.38内核的9500多个补丁中,只有112个(大约1.3%)是由Linus自己直接选择的。
内核项目已经发展到一个规模,没有一个开发人员可以在没有支持的情况下检查和
选择每个补丁。内核开发人员处理这种增长的方式是通过使用围绕信任链构建的
助理系统。
内核代码库在逻辑上被分解为一组子系统:网络、特定的体系结构支持、内存管理、
视频设备等。大多数子系统都有一个指定的维护人员,开发人员对该子系统中的代码
负有全部责任。这些子系统维护者(松散地)是他们所管理的内核部分的守护者;
他们(通常)会接受一个补丁以包含到主线内核中。
子系统维护人员每个人都使用git源代码管理工具管理自己版本的内核源代码树。Git
等工具(以及Quilt或Mercurial等相关工具)允许维护人员跟踪补丁列表,包括作者
信息和其他元数据。在任何给定的时间,维护人员都可以确定他或她的存储库中的哪
些补丁在主线中找不到。
当合并窗口打开时,顶级维护人员将要求Linus从其存储库中“拉出”他们为合并选择
的补丁。如果Linus同意,补丁流将流向他的存储库,成为主线内核的一部分。
Linus对拉操作中接收到的特定补丁的关注程度各不相同。很明显,有时他看起来很
关注。但是,作为一般规则,Linus相信子系统维护人员不会向上游发送坏补丁。
子系统维护人员反过来也可以从其他维护人员那里获取补丁。例如,网络树是由首先
在专用于网络设备驱动程序、无线网络等的树中积累的补丁构建的。此存储链可以
任意长,但很少超过两个或三个链接。由于链中的每个维护者都信任那些管理较低
级别树的维护者,所以这个过程称为“信任链”。
显然,在这样的系统中,获取内核补丁取决于找到正确的维护者。直接向Linus发送
补丁通常不是正确的方法。
Next 树
-------
子系统树链引导补丁流到内核,但它也提出了一个有趣的问题:如果有人想查看为
下一个合并窗口准备的所有补丁怎么办?开发人员将感兴趣的是,还有什么其他的
更改有待解决,以查看是否存在需要担心的冲突;例如,更改核心内核函数原型的
修补程序将与使用该函数旧形式的任何其他修补程序冲突。审查人员和测试人员希望
在所有这些变更到达主线内核之前,能够访问它们的集成形式中的变更。您可以从所有
有趣的子系统树中提取更改,但这将是一项大型且容易出错的工作。
答案以-next树的形式出现,在这里子系统树被收集以供测试和审查。Andrew Morton
维护的这些旧树被称为“-mm”(用于内存管理,这就是它的启动名字)。-mm 树集成了
一长串子系统树中的补丁;它还包含一些旨在帮助调试的补丁。
除此之外,-mm 还包含大量由Andrew直接选择的补丁。这些补丁可能已经发布在邮件
列表上,或者它们可能应用于内核中没有指定子系统树的部分。结果,-mm 作为一种
最后手段的子系统树运行;如果没有其他明显的路径可以让补丁进入主线,那么它很
可能以-mm 结束。累积在-mm 中的各种补丁最终将被转发到适当的子系统树,或者直接
发送到Linus。在典型的开发周期中,大约5-10%的补丁通过-mm 进入主线。
当前-mm 补丁可在“mmotm”(-mm of the moment)目录中找到,地址:
http://www.ozlabs.org/~akpm/mmotm/
然而,使用mmotm树可能是一种令人沮丧的体验;它甚至可能无法编译。
下一个周期补丁合并的主要树是linux-next,由Stephen Rothwell 维护。根据设计
linux-next 是下一个合并窗口关闭后主线的快照。linux-next树在Linux-kernel 和
Linux-next 邮件列表中发布,可从以下位置下载:
http://www.kernel.org/pub/linux/kernel/next/
Linux-next 已经成为内核开发过程中不可或缺的一部分;在一个给定的合并窗口中合并
的所有补丁都应该在合并窗口打开之前的一段时间内找到进入Linux-next 的方法。
Staging 树
----------
内核源代码树包含drivers/staging/directory,其中有许多驱动程序或文件系统的
子目录正在被添加到内核树中。它们然需要更多的工作的时候可以保留在
driver/staging目录中;一旦完成,就可以将它们移到内核中。这是一种跟踪不符合
Linux内核编码或质量标准的驱动程序的方法,但人们可能希望使用它们并跟踪开发。
Greg Kroah Hartman 目前负责维护staging 树。仍需要工作的驱动程序将发送给他,
每个驱动程序在drivers/staging/中都有自己的子目录。除了驱动程序源文件之外,
目录中还应该有一个TODO文件。todo文件列出了驱动程序需要接受的挂起的工作,
以及驱动程序的任何补丁都应该抄送的人员列表。当前的规则要求,staging的驱动
程序必须至少正确编译。
Staging 是一种相对容易的方法,可以让新的驱动程序进入主线,幸运的是,他们会
引起其他开发人员的注意,并迅速改进。然而,进入staging并不是故事的结尾;
staging中没有看到常规进展的代码最终将被删除。经销商也倾向于相对不愿意使用
staging驱动程序。因此,在成为一名合适的主线驱动的路上,staging 充其量只是
一个停留。
工具
----
从上面的文本可以看出,内核开发过程在很大程度上依赖于在不同方向上聚集补丁的
能力。如果没有适当强大的工具,整个系统将无法在任何地方正常工作。关于如何使用
这些工具的教程远远超出了本文档的范围,但是还是有一些指南的空间。
到目前为止,内核社区使用的主要源代码管理系统是git。Git是在自由软件社区中开发
的许多分布式版本控制系统之一。它非常适合内核开发,因为它在处理大型存储库和
大量补丁时性能非常好。它还有一个难以学习和使用的名声,尽管随着时间的推移它
变得更好了。对于内核开发人员来说,对Git的某种熟悉几乎是一种要求;即使他们不
将它用于自己的工作,他们也需要Git来跟上其他开发人员(以及主线)正在做的事情。
现在几乎所有的Linux发行版都打包了Git。主页位于:
http://git-scm.com/
那个页面有指向文档和教程的指针。
在不使用git的内核开发人员中,最流行的选择几乎肯定是mercurial:
http://www.seleric.com/mercurial/
Mercurial与Git共享许多特性,但它提供了一个界面,许多人觉得它更易于使用。
另一个值得了解的工具是quilt:
http://savannah.nongnu.org/projects/quilt
Quilt 是一个补丁管理系统,而不是源代码管理系统。它不会随着时间的推移跟踪历史;
相反,它面向根据不断发展的代码库跟踪一组特定的更改。一些主要的子系统维护人员
使用Quilt来管理打算向上游移动的补丁。对于某些树的管理(例如-mm),quilt 是
最好的工具。
邮件列表
--------
大量的Linux内核开发工作是通过邮件列表完成的。如果不在某个地方加入至少一个列表,
就很难成为社区中一个功能完备的成员。但是,Linux邮件列表对开发人员来说也是一个
潜在的危险,他们可能会被一堆电子邮件淹没,违反Linux列表上使用的约定,或者
两者兼而有之。
大多数内核邮件列表都在vger.kernel.org上运行;主列表位于:
http://vger.kernel.org/vger-lists.html
不过,也有一些列表托管在别处;其中一些列表位于lists.redhat.com。
当然,内核开发的核心邮件列表是linux-kernel。这个名单是一个令人生畏的地方;
每天的信息量可以达到500条,噪音很高,谈话技术性很强,参与者并不总是表现出
高度的礼貌。但是,没有其他地方可以让内核开发社区作为一个整体聚集在一起;
避免使用此列表的开发人员将错过重要信息。
有一些提示可以帮助在linux-kernel生存:
- 将邮件转移到单独的文件夹,而不是主邮箱。我们必须能够持续地忽略洪流。
- 不要试图跟踪每一次谈话-其他人都不会。重要的是要对感兴趣的主题(尽管请
注意,长时间的对话可以在不更改电子邮件主题行的情况下偏离原始主题)和参与
的人进行筛选。
- 不要挑事。如果有人试图激起愤怒的反应,忽略他们。
- 当响应Linux内核电子邮件(或其他列表上的电子邮件)时,请为所有相关人员保留
cc:header。如果没有强有力的理由(如明确的请求),则不应删除收件人。一定要
确保你要回复的人在cc:list中。这个惯例也使你不必在回复邮件时明确要求被抄送。
- 在提出问题之前,搜索列表档案(和整个网络)。有些开发人员可能会对那些显然
没有完成家庭作业的人感到不耐烦。
- 避免贴顶帖(把你的答案放在你要回复的引文上面的做法)。这会让你的回答更难
理解,印象也很差。
- 询问正确的邮件列表。linux-kernel 可能是通用的讨论点,但它不是从所有子系统
中寻找开发人员的最佳场所。
最后一点——找到正确的邮件列表——是开发人员出错的常见地方。在Linux内核上提出与
网络相关的问题的人几乎肯定会收到一个礼貌的建议,转而在netdev列表上提出,
因为这是大多数网络开发人员经常出现的列表。还有其他列表可用于scsi、
video4linux、ide、filesystem等子系统。查找邮件列表的最佳位置是与内核源代码
一起打包的MAINTAINERS文件。
开始内核开发
------------
关于如何开始内核开发过程的问题很常见——来自个人和公司。同样常见的是错误,这
使得关系的开始比必须的更困难。
公司通常希望聘请知名的开发人员来启动开发团队。实际上,这是一种有效的技术。
但它也往往是昂贵的,而且没有增长经验丰富的内核开发人员储备。考虑到时间的
投入,可以让内部开发人员加快Linux内核的开发速度。花这个时间可以让雇主拥有
一批了解内核和公司的开发人员,他们也可以帮助培训其他人。从中期来看,这往往
是更有利可图的方法。
可以理解的是,单个开发人员往往对起步感到茫然。从一个大型项目开始可能会很
吓人;人们往往想先用一些较小的东西来测试水域。这是一些开发人员开始创建修补
拼写错误或轻微编码风格问题的补丁的地方。不幸的是,这样的补丁会产生一定程度
的噪音,这会分散整个开发社区的注意力,因此,越来越多的人看不起它们。希望向
社区介绍自己的新开发人员将无法通过这些方式获得他们想要的那种接待。
Andrew Morton 为有抱负的内核开发人员提供了这个建议
::
所有内核初学者的No.1项目肯定是“确保内核在所有的机器上,你可以触摸
到的,始终运行良好" 通常这样做的方法是与其他人一起解决问题(这
可能需要坚持!)但这很好——这是内核开发的一部分
(http://lwn.net/articles/283982/)
在没有明显问题需要解决的情况下,建议开发人员查看当前的回归和开放式错误列表.
解决需要修复的问题没有任何缺点;通过解决这些问题,开发人员将获得处理过程的
经验,同时与开发社区的其他人建立尊重。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/3.Early-stage.rst <development_early_stage>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_early_stage:
早期规划
========
当考虑一个Linux内核开发项目时,很可能会直接跳进去开始编码。然而,与任何重要
的项目一样,成功的许多基础最好是在第一行代码编写之前就做好了。在早期计划和
沟通中花费一些时间可以节省更多的时间。
详述问题
--------
与任何工程项目一样,成功的内核增强从要解决的问题的清晰描述开始。在某些情况
下,这个步骤很容易:例如,当某个特定硬件需要驱动程序时。不过,在其他方面,
将实际问题与建议的解决方案混淆是很有诱惑力的,这可能会导致困难。
举个例子:几年前,使用Linux音频的开发人员寻求一种方法来运行应用程序,而不因
系统延迟过大而导致退出或其他工件。他们得到的解决方案是一个内核模块,旨在连
接到Linux安全模块(LSM)框架中;这个模块可以配置为允许特定的应用程序访问
实时调度程序。这个模块被实现并发送到Linux内核邮件列表,在那里它立即遇到问题。
对于音频开发人员来说,这个安全模块足以解决他们当前的问题。但是,对于更广泛的
内核社区来说,这被视为对LSM框架的滥用(LSM框架并不打算授予他们原本不具备的
进程特权),并对系统稳定性造成风险。他们首选的解决方案包括短期的通过rlimit
机制进行实时调度访问,以及长期的减少延迟的工作。
然而,音频社区看不到他们实施的特定解决方案的过去;他们不愿意接受替代方案。
由此产生的分歧使这些开发人员对整个内核开发过程感到失望;其中一个开发人员返回
到音频列表并发布了以下内容:
有很多非常好的Linux内核开发人员,但他们往往会被一群傲慢的傻瓜所压倒。
试图向这些人传达用户需求是浪费时间。他们太“聪明”了,根本听不到少数人
的话。
(http://lwn.net/articles/131776/)
实际情况不同;与特定模块相比,内核开发人员更关心系统稳定性、长期维护以及找到
正确的问题解决方案。这个故事的寓意是把重点放在问题上——而不是具体的解决方案
上——并在投入创建代码之前与开发社区讨论这个问题。
因此,在考虑一个内核开发项目时,我们应该得到一组简短问题的答案:
- 究竟需要解决的问题是什么?
- 受此问题影响的用户是谁?解决方案应该解决哪些用例?
- 内核现在为何没能解决这个问题?
只有这样,才能开始考虑可能的解决方案。
早期讨论
--------
在计划内核开发项目时,在开始实施之前与社区进行讨论是很有意义的。早期沟通可以
通过多种方式节省时间和麻烦:
- 很可能问题是由内核以您不理解的方式解决的。Linux内核很大,具有许多不明显
的特性和功能。并不是所有的内核功能都像人们所希望的那样有文档记录,而且很
容易遗漏一些东西。你的作者发出了一个完整的驱动程序,复制了一个新作者不
知道的现有驱动程序。重新设计现有轮子的代码不仅浪费,而且不会被接受到主线
内核中。
- 建议的解决方案中可能有一些元素不适用于主线合并。在编写代码之前,最好先
了解这样的问题。
- 其他开发人员完全有可能考虑过这个问题;他们可能有更好的解决方案的想法,并且
可能愿意帮助创建这个解决方案。
在内核开发社区的多年经验给了我们一个明确的教训:闭门设计和开发的内核代码总是
有一些问题,这些问题只有在代码发布到社区中时才会被发现。有时这些问题很严重,
需要数月或数年的努力才能使代码达到内核社区的标准。一些例子包括:
- 设计并实现了单处理器系统的DeviceScape网络栈。只有使其适合于多处理器系统,
才能将其合并到主线中。在代码中改装锁等等是一项困难的任务;因此,这段代码
(现在称为mac80211)的合并被推迟了一年多。
- Reiser4文件系统包含许多功能,核心内核开发人员认为这些功能应该在虚拟文件
系统层中实现。它还包括一些特性,这些特性在不将系统暴露于用户引起的死锁的
情况下是不容易实现的。这些问题的最新发现——以及对其中一些问题的拒绝——已经
导致Reiser4远离了主线内核。
- Apparmor安全模块以被认为不安全和不可靠的方式使用内部虚拟文件系统数据结构。
这种担心(包括其他)使Apparmor多年不在主线上。
在每一种情况下,通过与内核开发人员的早期讨论,可以避免大量的痛苦和额外的工作。
找谁交流
--------
当开发人员决定公开他们的计划时,下一个问题是:我们从哪里开始?答案是找到正确
的邮件列表和正确的维护者。对于邮件列表,最好的方法是在维护者(MAINTAINERS)文件
中查找要发布的相关位置。如果有一个合适的子系统列表,那么发布它通常比在Linux
内核上发布更可取;您更有可能接触到在相关子系统中具有专业知识的开发人员,并且
环境可能具支持性。
找到维护人员可能会有点困难。同样,维护者文件是开始的地方。但是,该文件往往不总
是最新的,并且并非所有子系统都在那里表示。实际上,维护者文件中列出的人员可能
不是当前实际担任该角色的人员。因此,当对联系谁有疑问时,一个有用的技巧是使用
git(尤其是“git-log”)查看感兴趣的子系统中当前活动的用户。看看谁在写补丁,
如果有人的话,谁会在这些补丁上加上用线签名的。这些人将是帮助新开发项目的最佳
人选。
找到合适的维护者的任务有时是非常具有挑战性的,以至于内核开发人员添加了一个
脚本来简化过程:
::
.../scripts/get_maintainer.pl
当给定“-f”选项时,此脚本将返回给定文件或目录的当前维护者。如果在命令行上传递
了一个补丁,它将列出可能接收补丁副本的维护人员。有许多选项可以调节
get_maintainer.pl搜索维护者的难易程度;请小心使用更具攻击性的选项,因为最终
可能会包括对您正在修改的代码没有真正兴趣的开发人员。
如果所有其他方法都失败了,那么与Andrew Morton交谈可以成为一种有效的方法来跟踪
特定代码段的维护人员。
何时邮寄?
----------
如果可能的话,在早期阶段发布你的计划只会有帮助。描述正在解决的问题以及已经
制定的关于如何实施的任何计划。您可以提供的任何信息都可以帮助开发社区为项目
提供有用的输入。
在这个阶段可能发生的一件令人沮丧的事情不是敌对的反应,而是很少或根本没有
反应。可悲的事实是:(1)内核开发人员往往很忙;(2)不缺少有宏伟计划和很少
代码(甚至代码前景)支持他们的人;(3)没有人有义务审查或评论别人发表的
想法。除此之外,高级设计常常隐藏一些问题,这些问题只有在有人真正尝试实现
这些设计时才会被发现;因此,内核开发人员宁愿看到代码。
如果发表评论的请求在评论的方式上没有什么效果,不要假设这意味着对项目没有
兴趣。不幸的是,你也不能假设你的想法没有问题。在这种情况下,最好的做法是
继续进行,把你的进展随时通知社区。
获得官方认可
-----------------------
如果您的工作是在公司环境中完成的,就像大多数Linux内核工作一样,显然,在您将
公司的计划或代码发布到公共邮件列表之前,必须获得适当授权的经理的许可。发布
不确定是否兼容GPL的代码可能是有特别问题的;公司的管理层和法律人员越早能够就
发布内核开发项目达成一致,对参与的每个人都越好。
一些读者可能会认为他们的核心工作是为了支持还没有正式承认存在的产品。将雇主
的计划公布在公共邮件列表上可能不是一个可行的选择。在这种情况下,有必要考虑
保密是否真的是必要的;通常不需要把开发计划关在门内。
也就是说,有些情况下,一家公司在开发过程的早期就不能合法地披露其计划。拥有
经验丰富的内核开发人员的公司可以选择以开环的方式进行,前提是他们以后能够避免
严重的集成问题。对于没有这种内部专业知识的公司,最好的选择往往是聘请外部
开发商根据保密协议审查计划。Linux基金会运行了一个NDA程序,旨在帮助解决这种
情况;
http://www.linuxfoundation.org/en/NDA_program
这种审查通常足以避免以后出现严重问题,而无需公开披露项目。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/4.Coding.rst <development_coding>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_coding:
使代码正确
======================
虽然对于一个坚实的、面向社区的设计过程有很多话要说,但是任何内核开发项目的
证明都在生成的代码中。它是将由其他开发人员检查并合并(或不合并)到主线树中
的代码。所以这段代码的质量决定了项目的最终成功。
本节将检查编码过程。我们将从内核开发人员出错的几种方式开始。然后重点将转移
到正确的事情和可以帮助这个任务的工具上。
陷阱
----
编码风格
********
内核长期以来都有一种标准的编码风格,如
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
中所述。在大部分时间里,该文件中描述的政策被认为至多是建议性的。因此,内核
中存在大量不符合编码风格准则的代码。代码的存在会给内核开发人员带来两个独立
的危害。
首先,要相信内核编码标准并不重要,也不强制执行。事实上,如果没有按照标准对代
码进行编码,那么向内核添加新代码是非常困难的;许多开发人员甚至会在审查代码之
前要求对代码进行重新格式化。一个与内核一样大的代码库需要一些统一的代码,以使
开发人员能够快速理解其中的任何部分。所以已经没有空间来存放奇怪的格式化代码了。
偶尔,内核的编码风格会与雇主的强制风格发生冲突。在这种情况下,内核的风格必须
在代码合并之前获胜。将代码放入内核意味着以多种方式放弃一定程度的控制权——包括
控制代码的格式化方式。
另一个陷阱是假定已经在内核中的代码迫切需要编码样式的修复。开发人员可能会开始
生成重新格式化补丁,作为熟悉过程的一种方式,或者作为将其名称写入内核变更日志
的一种方式,或者两者兼而有之。但是纯编码风格的修复被开发社区视为噪音;它们往
往受到冷遇。因此,最好避免使用这种类型的补丁。由于其他原因,在处理一段代码的
同时修复它的样式是很自然的,但是编码样式的更改不应该仅为了更改而进行。
编码风格的文档也不应该被视为绝对的法律,这是永远不会被违反的。如果有一个很好
的理由反对这种样式(例如,如果拆分为适合80列限制的行,那么它的可读性就会大大
降低),那么就这样做。
请注意,您还可以使用 ``clang-format`` 工具来帮助您处理这些规则,自动重新格式
化部分代码,并查看完整的文件,以发现编码样式错误、拼写错误和可能的改进。它还
可以方便地进行排序,包括对齐变量/宏、回流文本和其他类似任务。有关详细信息,请
参阅文件 :ref:`Documentation/process/clang-format.rst <clangformat>`
抽象层
******
计算机科学教授教学生以灵活性和信息隐藏的名义广泛使用抽象层。当然,内核广泛
地使用了抽象;任何涉及数百万行代码的项目都不能做到这一点并存活下来。但经验
表明,过度或过早的抽象可能和过早的优化一样有害。抽象应用于所需的级别,
不要过度。
在一个简单的级别上,考虑一个函数的参数,该参数总是由所有调用方作为零传递。
我们可以保留这个论点: 以防有人最终需要使用它提供的额外灵活性。不过,到那时,
实现这个额外参数的代码很有可能以某种从未被注意到的微妙方式被破坏——因为它从
未被使用过。或者,当需要额外的灵活性时,它不会以符合程序员早期期望的方式来
这样做。内核开发人员通常会提交补丁来删除未使用的参数;一般来说,首先不应该
添加这些参数。
隐藏硬件访问的抽象层——通常允许大量的驱动程序在多个操作系统中使用——尤其不受
欢迎。这样的层使代码变得模糊,可能会造成性能损失;它们不属于Linux内核。
另一方面,如果您发现自己从另一个内核子系统复制了大量的代码,那么现在是时候
问一下,事实上,将这些代码中的一些提取到单独的库中,或者在更高的层次上实现
这些功能是否有意义。在整个内核中复制相同的代码没有价值。
#ifdef 和预处理
***************
C预处理器似乎给一些C程序员带来了强大的诱惑,他们认为它是一种有效地将大量灵
活性编码到源文件中的方法。但是预处理器不是C,大量使用它会导致代码对其他人来
说更难读取,对编译器来说更难检查正确性。大量的预处理器几乎总是代码需要一些
清理工作的标志。
使用ifdef的条件编译实际上是一个强大的功能,它在内核中使用。但是很少有人希望
看到代码被大量地撒上ifdef块。作为一般规则,ifdef的使用应尽可能限制在头文件
中。有条件编译的代码可以限制函数,如果代码不存在,这些函数就会变成空的。然后
编译器将悄悄地优化对空函数的调用。结果是代码更加清晰,更容易理解。
C预处理器宏存在许多危险,包括可能对具有副作用且没有类型安全性的表达式进行多
重评估。如果您试图定义宏,请考虑创建一个内联函数。结果相同的代码,但是内联
函数更容易读取,不会多次计算其参数,并且允许编译器对参数和返回值执行类型检查。
内联函数
********
不过,内联函数本身也存在风险。程序员可以倾心于避免函数调用和用内联函数填充源
文件所固有的效率。然而,这些功能实际上会降低性能。因为它们的代码在每个调用站
点都被复制,所以它们最终会增加编译内核的大小。反过来,这会对处理器的内存缓存
造成压力,从而大大降低执行速度。通常,内联函数应该非常小,而且相对较少。毕竟,
函数调用的成本并不高;大量内联函数的创建是过早优化的典型例子。
一般来说,内核程序员会忽略缓存效果,这会带来危险。在开始的数据结构课程中,经
典的时间/空间权衡通常不适用于当代硬件。空间就是时间,因为一个大的程序比一个
更紧凑的程序运行得慢。
最近的编译器在决定一个给定函数是否应该被内联方面扮演着越来越积极的角色。
因此,“inline”关键字的自由放置可能不仅仅是过度的,它也可能是无关的。
**
2006年5月,“deviceescape”网络堆栈在GPL下发布,并被纳入主线内核。这是一个受
欢迎的消息;对Linux中无线网络的支持充其量被认为是不合格的,而deviceescape
堆栈提供了修复这种情况的承诺。然而,直到2007年6月(2.6.22),这段代码才真
正进入主线。发生了什么?
这段代码显示了许多闭门造车的迹象。但一个特别大的问题是,它并不是设计用于多
处理器系统。在合并这个网络堆栈(现在称为mac80211)之前,需要对其进行一个锁
方案的改造。
曾经,Linux内核代码可以在不考虑多处理器系统所带来的并发性问题的情况下进行
开发。然而,现在,这个文件是写在双核笔记本电脑上的。即使在单处理器系统上,
为提高响应能力所做的工作也会提高内核内的并发性水平。编写内核代码而不考虑锁
的日子已经过去很长了。
可以由多个线程并发访问的任何资源(数据结构、硬件寄存器等)必须由锁保护。新
的代码应该记住这一要求;事后改装锁是一项相当困难的任务。内核开发人员应该花
时间充分了解可用的锁原语,以便为作业选择正确的工具。显示对并发性缺乏关注的
代码进入主线将很困难。
回归
****
最后一个值得一提的危险是:它可能会引起改变(这可能会带来很大的改进),从而
导致现有用户的某些东西中断。这种变化被称为“回归”,回归已经成为主线内核最不
受欢迎的。除少数例外情况外,如果回归不能及时修正,会导致回归的变化将被取消。
最好首先避免回归。
人们常常争论,如果回归让更多人可以工作,远超过产生问题,那么回归是合理的。
如果它破坏的一个系统却为十个系统带来新的功能,为什么不进行更改呢?2007年7月,
Linus对这个问题给出了最佳答案:
::
所以我们不会通过引入新问题来修复错误。那样的谎言很疯狂,没有人知道
你是否真的有进展。是前进两步,后退一步,还是向前一步,向后两步?
(http://lwn.net/articles/243460/)
一种特别不受欢迎的回归类型是用户空间ABI的任何变化。一旦接口被导出到用户空间,
就必须无限期地支持它。这一事实使得用户空间接口的创建特别具有挑战性:因为它们
不能以不兼容的方式进行更改,所以必须第一次正确地进行更改。因此,用户空间界面
总是需要大量的思考、清晰的文档和广泛的审查。
代码检查工具
------------
至少目前,编写无错误代码仍然是我们中很少人能达到的理想状态。不过,我们希望做
的是,在代码进入主线内核之前,尽可能多地捕获并修复这些错误。为此,内核开发人
员已经组装了一系列令人印象深刻的工具,可以自动捕获各种各样的模糊问题。计算机
发现的任何问题都是一个以后不会困扰用户的问题,因此,只要有可能,就应该使用
自动化工具。
第一步只是注意编译器产生的警告。当代版本的GCC可以检测(并警告)大量潜在错误。
通常,这些警告都指向真正的问题。提交以供审阅的代码通常不会产生任何编译器警告。
在消除警告时,注意了解真正的原因,并尽量避免“修复”,使警告消失而不解决其原因。
请注意,并非所有编译器警告都默认启用。使用“make EXTRA_CFLAGS=-W”构建内核以
获得完整集合。
内核提供了几个配置选项,可以打开调试功能;大多数配置选项位于“kernel hacking”
子菜单中。对于任何用于开发或测试目的的内核,都应该启用其中几个选项。特别是,
您应该打开:
- 启用 ENABLE_MUST_CHECK and FRAME_WARN 以获得一组额外的警告,以解决使用不
推荐使用的接口或忽略函数的重要返回值等问题。这些警告生成的输出可能是冗长
的,但您不必担心来自内核其他部分的警告。
- DEBUG_OBJECTS 将添加代码,以跟踪内核创建的各种对象的生存期,并在出现问题时
发出警告。如果要添加创建(和导出)自己的复杂对象的子系统,请考虑添加对对象
调试基础结构的支持。
- DEBUG_SLAB 可以发现各种内存分配和使用错误;它应该用于大多数开发内核。
- DEBUG_SPINLOCK, DEBUG_ATOMIC_SLEEP and DEBUG_MUTEXES 会发现许多常见的
锁定错误.
还有很多其他调试选项,其中一些将在下面讨论。其中一些具有显著的性能影响,不应
一直使用。但是,在学习可用选项上花费的一些时间可能会在短期内得到多次回报。
其中一个较重的调试工具是锁定检查器或“lockdep”。该工具将跟踪系统中每个锁
(spinlock或mutex)的获取和释放、获取锁的相对顺序、当前中断环境等等。然后,
它可以确保总是以相同的顺序获取锁,相同的中断假设适用于所有情况,等等。换句话
说,lockdep可以找到许多场景,在这些场景中,系统很少会死锁。在部署的系统中,
这种问题可能会很痛苦(对于开发人员和用户而言);LockDep允许提前以自动方式
发现问题。具有任何类型的非普通锁定的代码在提交包含前应在启用lockdep的情况
下运行。
作为一个勤奋的内核程序员,毫无疑问,您将检查任何可能失败的操作(如内存分配)
的返回状态。然而,事实上,最终的故障恢复路径可能完全没有经过测试。未测试的
代码往往会被破坏;如果所有这些错误处理路径都被执行了几次,那么您可能对代码
更有信心。
内核提供了一个可以做到这一点的错误注入框架,特别是在涉及内存分配的情况下。
启用故障注入后,内存分配的可配置百分比将失败;这些失败可以限制在特定的代码
范围内。在启用了故障注入的情况下运行,程序员可以看到当情况恶化时代码如何响
应。有关如何使用此工具的详细信息,请参阅
Documentation/fault-injection/fault-injection.txt。
使用“sparse”静态分析工具可以发现其他类型的错误。对于sparse,可以警告程序员
用户空间和内核空间地址之间的混淆、big endian和small endian数量的混合、在需
要一组位标志的地方传递整数值等等。sparse必须单独安装(如果您的分发服务器没
有将其打包,可以在 https://sparse.wiki.kernel.org/index.php/Main_page)找到,
然后可以通过在make命令中添加“C=1”在代码上运行它。
“Coccinelle”工具 :ref:`http://coccinelle.lip6.fr/ <devtools_coccinelle>`
能够发现各种潜在的编码问题;它还可以为这些问题提出修复方案。在
scripts/coccinelle目录下已经打包了相当多的内核“语义补丁”;运行
“make coccicheck”将运行这些语义补丁并报告发现的任何问题。有关详细信息,请参阅
:ref:`Documentation/dev-tools/coccinelle.rst <devtools_coccinelle>`
其他类型的可移植性错误最好通过为其他体系结构编译代码来发现。如果没有S/390系统
或Blackfin开发板,您仍然可以执行编译步骤。可以在以下位置找到一组用于x86系统的
大型交叉编译器:
http://www.kernel.org/pub/tools/crosstool/
花一些时间安装和使用这些编译器将有助于避免以后的尴尬。
文档
----
文档通常比内核开发规则更为例外。即便如此,足够的文档将有助于简化将新代码合并
到内核中的过程,使其他开发人员的生活更轻松,并对您的用户有所帮助。在许多情况
下,文件的添加已基本上成为强制性的。
任何补丁的第一个文档是其关联的变更日志。日志条目应该描述正在解决的问题、解决
方案的形式、处理补丁的人员、对性能的任何相关影响,以及理解补丁可能需要的任何
其他内容。确保changelog说明了为什么补丁值得应用;大量开发人员未能提供这些信息。
任何添加新用户空间界面的代码(包括新的sysfs或/proc文件)都应该包含该界面的
文档,该文档使用户空间开发人员能够知道他们在使用什么。请参阅
Documentation/abi/readme,了解如何格式化此文档以及需要提供哪些信息。
文件 :ref:`Documentation/admin-guide/kernel-parameters.rst <kernelparameters>`
描述了内核的所有引导时间参数。任何添加新参数的补丁都应该向该文件添加适当的
条目。
任何新的配置选项都必须附有帮助文本,帮助文本清楚地解释了这些选项以及用户可能
希望何时选择它们。
许多子系统的内部API信息通过专门格式化的注释进行记录;这些注释可以通过
“kernel-doc”脚本以多种方式提取和格式化。如果您在具有kerneldoc注释的子系统中
工作,则应该维护它们,并根据需要为外部可用的功能添加它们。即使在没有如此记录
的领域中,为将来添加kerneldoc注释也没有坏处;实际上,这对于刚开始开发内核的人
来说是一个有用的活动。这些注释的格式以及如何创建kerneldoc模板的一些信息可以在
:ref:`Documentation/doc-guide/ <doc_guide>` 上找到。
任何阅读大量现有内核代码的人都会注意到,注释的缺失往往是最值得注意的。再一次,
对新代码的期望比过去更高;合并未注释的代码将更加困难。这就是说,人们几乎不希望
用语言注释代码。代码本身应该是可读的,注释解释了更微妙的方面。
某些事情应该总是被注释。使用内存屏障时,应附上一行文字,解释为什么需要设置内存
屏障。数据结构的锁定规则通常需要在某个地方解释。一般来说,主要数据结构需要全面
的文档。应该指出单独代码位之间不明显的依赖性。任何可能诱使代码看门人进行错误的
“清理”的事情都需要一个注释来说明为什么要这样做。等等。
内部API更改
-----------
内核提供给用户空间的二进制接口不能被破坏,除非在最严重的情况下。相反,内核的
内部编程接口是高度流动的,当需要时可以更改。如果你发现自己不得不处理一个内核
API,或者仅仅因为它不满足你的需求而不使用特定的功能,这可能是API需要改变的一
个标志。作为内核开发人员,您有权进行此类更改。
当然, 可以进行API更改,但它们必须是合理的。因此,任何进行内部API更改的补丁都
应该附带一个关于更改内容和必要原因的描述。这种变化也应该分解成一个单独的补丁,
而不是埋在一个更大的补丁中。
另一个要点是,更改内部API的开发人员通常要负责修复内核树中被更改破坏的任何代码。
对于一个广泛使用的函数,这个职责可以导致成百上千的变化,其中许多变化可能与其他
开发人员正在做的工作相冲突。不用说,这可能是一项大工作,所以最好确保理由是
可靠的。请注意,coccinelle工具可以帮助进行广泛的API更改。
在进行不兼容的API更改时,应尽可能确保编译器捕获未更新的代码。这将帮助您确保找
到该接口的树内用处。它还将警告开发人员树外代码存在他们需要响应的更改。支持树外
代码不是内核开发人员需要担心的事情,但是我们也不必使树外开发人员的生活有不必要
的困难。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/5.Posting.rst <development_posting>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_posting:
发送补丁
========
迟早,当您的工作准备好提交给社区进行审查,并最终包含到主线内核中时。不出所料,
内核开发社区已经发展出一套用于发布补丁的约定和过程;遵循这些约定和过程将使
参与其中的每个人的生活更加轻松。本文件将试图合理详细地涵盖这些期望;更多信息
也可在以下文件中找到
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`,
:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
和 :ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`.
何时邮寄
--------
在补丁完全“准备好”之前,有一个不断的诱惑来避免发布补丁。对于简单的补丁,
这不是问题。但是,如果正在完成的工作很复杂,那么在工作完成之前从社区获得
反馈就可以获得很多好处。因此,您应该考虑发布正在进行的工作,甚至使Git树
可用,以便感兴趣的开发人员可以随时赶上您的工作。
当发布还没有准备好包含的代码时,最好在发布本身中这样说。还应提及任何有待完成
的主要工作和任何已知问题。很少有人会看到那些被认为是半生不熟的补丁,但是那些
人会想到他们可以帮助你把工作推向正确的方向。
创建补丁之前
------------
在考虑将补丁发送到开发社区之前,有许多事情应该做。这些包括:
- 尽可能地测试代码。利用内核的调试工具,确保内核使用所有合理的配置选项组合
进行构建,使用跨编译器为不同的体系结构进行构建等。
- 确保您的代码符合内核编码风格指南。
- 您的更改是否具有性能影响?如果是这样,您应该运行基准测试来显示您的变更的
影响(或好处);结果的摘要应该包含在补丁中。
- 确保您有权发布代码。如果这项工作是为雇主完成的,雇主对这项工作具有所有权,
并且必须同意根据GPL对其进行放行。
一般来说,在发布代码之前进行一些额外的思考,几乎总是能在短时间内得到回报。
补丁准备
--------
准备发布补丁可能是一个惊人的工作量,但再次尝试节省时间在这里通常是不明智的,
即使在短期内。
必须针对内核的特定版本准备补丁。作为一般规则,补丁程序应该基于Linus的Git树中
的当前主线。当以主线为基础时,从一个众所周知的发布点开始——一个稳定的或RC的
发布——而不是在一个主线分支任意点。
但是,可能需要针对-mm、linux-next或子系统树生成版本,以便于更广泛的测试和审查。
根据补丁的区域以及其他地方的情况,针对这些其他树建立补丁可能需要大量的工作来
解决冲突和处理API更改。
只有最简单的更改才应格式化为单个补丁;其他所有更改都应作为一系列逻辑更改进行。
分割补丁是一门艺术;一些开发人员花了很长时间来弄清楚如何按照社区期望的方式来
做。然而,有一些经验法则可以大大帮助:
- 您发布的补丁程序系列几乎肯定不会是工作系统中的一系列更改。相反,您所做的
更改需要在最终形式中加以考虑,然后以有意义的方式进行拆分。开发人员对离散的、
自包含的更改感兴趣,而不是您获取这些更改的路径。
- 每个逻辑上独立的变更都应该格式化为单独的补丁。这些更改可以是小的(“向此
结构添加字段”)或大的(例如,添加一个重要的新驱动程序),但它们在概念上
应该是小的,并且可以接受一行描述。每个补丁都应该做一个特定的更改,可以单独
检查并验证它所做的事情。
- 作为重申上述准则的一种方法:不要在同一补丁中混合不同类型的更改。如果一个
补丁修复了一个关键的安全漏洞,重新排列了一些结构,并重新格式化了代码,那么
很有可能它会被忽略,而重要的修复将丢失。
- 每个补丁都应该产生一个内核,它可以正确地构建和运行;如果补丁系列在中间被
中断,那么结果应该仍然是一个工作的内核。补丁系列的部分应用是使用
“git bisct”工具查找回归的一个常见场景;如果结果是一个损坏的内核,那么对于
那些从事追踪问题的高尚工作的开发人员和用户来说,将使他们的生活更加艰难。
- 不过,不要过分。一位开发人员曾经将一组编辑内容作为500个单独的补丁发布到一个
文件中,这并没有使他成为内核邮件列表中最受欢迎的人。一个补丁可以相当大,
只要它仍然包含一个单一的逻辑变更。
- 用一系列补丁添加一个全新的基础设施是很有诱惑力的,但是在系列中的最后一个
补丁启用整个补丁之前,该基础设施是不使用的。如果可能的话,应该避免这种
诱惑;如果这个系列增加了回归,那么二分法将指出最后一个补丁是导致问题的
补丁,即使真正的bug在其他地方。只要有可能,添加新代码的补丁程序应该立即
激活该代码。
创建完美补丁系列的工作可能是一个令人沮丧的过程,在完成“真正的工作”之后需要花费
大量的时间和思考。但是,如果做得好,这是一段很好的时间。
补丁格式和更改日志
------------------
所以现在你有了一系列完美的补丁可以发布,但是这项工作还没有完成。每个补丁都
需要被格式化成一条消息,它可以快速而清晰地将其目的传达给世界其他地方。为此,
每个补丁将由以下部分组成:
- 命名补丁作者的可选“from”行。只有当你通过电子邮件传递别人的补丁时,这一行
才是必要的,但是如果有疑问,添加它不会有任何伤害。
- 一行描述补丁的作用。对于没有其他上下文的读者来说,此消息应该足够了解补丁
的范围;这是将在“短格式”变更日志中显示的行。此消息通常首先用相关的子系统
名称格式化,然后是补丁的目的。例如:
::
gpio: fix build on CONFIG_GPIO_SYSFS=n
- 一个空白行,后面是补丁内容的详细描述。这个描述可以是必需的;它应该说明补丁
的作用以及为什么它应该应用于内核。
- 一个或多个标记行,至少有一个由补丁作者的:signed-off-by 签名。签名将在下面
更详细地描述。
上面的项目一起构成补丁的变更日志。写一篇好的变更日志是一门至关重要但常常被
忽视的艺术;值得花一点时间来讨论这个问题。当你写一个变更日志时,你应该记住
有很多不同的人会读你的话。其中包括子系统维护人员和审查人员,他们需要决定是否
应该包括补丁,分销商和其他维护人员试图决定是否应该将补丁反向移植到其他内核,
bug搜寻人员想知道补丁是否负责他们正在追查的问题,想知道内核如何变化的用户。
等等。一个好的变更日志以最直接和最简洁的方式向所有这些人传达所需的信息。
为此,总结行应该描述变更的影响和动机,以及在一行约束条件下可能发生的变化。
然后,详细的描述可以详述这些主题,并提供任何需要的附加信息。如果补丁修复了
一个bug,请引用引入该bug的commit(如果可能,请在引用commits时同时提供commit id
和标题)。如果某个问题与特定的日志或编译器输出相关联,请包含该输出以帮助其他
人搜索同一问题的解决方案。如果更改是为了支持以后补丁中的其他更改,那么就这么
说。如果更改了内部API,请详细说明这些更改以及其他开发人员应该如何响应。一般
来说,你越能把自己放在每个阅读你的changelog的人的位置上,changelog(和内核
作为一个整体)就越好。
不用说,变更日志应该是将变更提交到修订控制系统时使用的文本。接下来是:
- 补丁本身,采用统一的(“-u”)补丁格式。将“-p”选项用于diff将使函数名与更改
相关联,从而使结果补丁更容易被其他人读取。
您应该避免在补丁中包括对不相关文件(例如,由构建过程生成的文件或编辑器
备份文件)的更改。文档目录中的文件“dontdiff”在这方面有帮助;使用“-X”选项将
其传递给diff。
上面提到的标签用于描述各种开发人员如何与这个补丁的开发相关联。
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
文档中对它们进行了详细描述;下面是一个简短的总结。每一行的格式如下:
::
tag: Full Name <email address> optional-other-stuff
常用的标签有:
- Signed-off-by: 这是一个开发人员的证明,他或她有权提交补丁以包含到内核中。
这是开发来源认证协议,其全文可在
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
中找到,如果没有适当的签字,则不能合并到主线中。
- Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上
工作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为
Co-developed-by: 表示作者身份,所以每个共同开发人, 必须紧跟在相关合作作者
的签名之后。具体内容和示例可以在以下文件中找到
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- Acked-by: 表示另一个开发人员(通常是相关代码的维护人员)同意补丁适合包含
在内核中。
- Tested-by: 声明指定的人已经测试了补丁并发现它可以工作。
- Reviewed-by: 指定的开发人员已经审查了补丁的正确性;有关详细信息,请参阅
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
- Reported-by: 指定报告此补丁修复的问题的用户;此标记用于提供感谢。
- Cc:指定的人收到了补丁的副本,并有机会对此发表评论。
在补丁中添加标签时要小心:只有cc:才适合在没有指定人员明确许可的情况下添加。
发送补丁
--------
在邮寄补丁之前,您还需要注意以下几点:
- 您确定您的邮件发送程序不会损坏补丁吗?有免费的空白更改或由邮件客户端
执行的行包装的补丁不会在另一端复原,并且通常不会进行任何详细检查。如果有
任何疑问,把补丁寄给你自己,让你自己相信它是完好无损的。
:ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>`
提供了一些有用的提示,可以让特定的邮件客户机工作以发送补丁。
- 你确定你的补丁没有愚蠢的错误吗?您应该始终通过scripts/checkpatch.pl运行
补丁程序,并解决它提出的投诉。请记住,checkpatch.pl虽然是大量思考内核
补丁应该是什么样子的体现,但它并不比您聪明。如果修复checkpatch.pl投诉会
使代码变得更糟,请不要这样做。
补丁应始终以纯文本形式发送。请不要将它们作为附件发送;这使得审阅者在答复中更难
引用补丁的部分。相反,只需将补丁直接放到您的消息中。
邮寄补丁时,重要的是将副本发送给任何可能感兴趣的人。与其他一些项目不同,内核
鼓励人们错误地发送过多的副本;不要假定相关人员会看到您在邮件列表中的发布。
尤其是,副本应发送至:
- 受影响子系统的维护人员。如前所述,维护人员文件是查找这些人员的第一个地方。
- 其他在同一领域工作的开发人员,尤其是那些现在可能在那里工作的开发人员。使用
git查看还有谁修改了您正在处理的文件,这很有帮助。
- 如果您对错误报告或功能请求做出响应,也可以抄送原始发送人。
- 将副本发送到相关邮件列表,或者,如果没有其他应用,则发送到Linux内核列表。
- 如果您正在修复一个bug,请考虑该修复是否应进入下一个稳定更新。如果是这样,
stable@vger.kernel.org 应该得到补丁的副本。另外,在补丁本身的标签中添加
一个“cc:stable@vger.kernel.org”;这将使稳定团队在修复进入主线时收到通知。
当为一个补丁选择接收者时,最好知道你认为谁最终会接受这个补丁并将其合并。虽然
可以将补丁直接发送给LinusTorvalds并让他合并,但通常情况下不会这样做。Linus
很忙,并且有子系统维护人员负责监视内核的特定部分。通常您会希望维护人员合并您
的补丁。如果没有明显的维护人员,Andrew Morton通常是最后的补丁目标。
补丁需要好的主题行。补丁程序行的规范格式如下:
::
[PATCH nn/mm] subsys: one-line description of the patch
其中“nn”是补丁的序号,“mm”是系列中补丁的总数,“subsys”是受影响子系统的名称。
显然,一个单独的补丁可以省略nn/mm。
如果您有一系列重要的补丁,那么通常将介绍性描述作为零部分发送。不过,这种约定
并没有得到普遍遵循;如果您使用它,请记住简介中的信息不会使它进入内核变更日志。
因此,请确保补丁本身具有完整的变更日志信息。
一般来说,多部分补丁的第二部分和后续部分应作为对第一部分的回复发送,以便它们
在接收端都连接在一起。像git和coilt这样的工具有命令,可以通过适当的线程发送
一组补丁。但是,如果您有一个长系列,并且正在使用git,请远离–chain reply-to
选项,以避免创建异常深的嵌套。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/6.Followthrough.rst <development_followthrough>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_followthrough:
跟进
====
在这一点上,您已经遵循了到目前为止给出的指导方针,并且,随着您自己的工程技能
的增加,已经发布了一系列完美的补丁。即使是经验丰富的内核开发人员也能犯的最大
错误之一是,认为他们的工作现在已经完成了。事实上,发布补丁意味着进入流程的下
一个阶段,可能还需要做很多工作。
一个补丁在第一次发布时就非常出色,没有改进的余地,这是很罕见的。内核开发流程
认识到这一事实,因此,它非常注重对已发布代码的改进。作为代码的作者,您应该与
内核社区合作,以确保您的代码符合内核的质量标准。如果不参与这个过程,很可能会
阻止将补丁包含到主线中。
与审阅者合作
------------
任何意义上的补丁都会导致其他开发人员在审查代码时发表大量评论。对于许多开发
人员来说,与审查人员合作可能是内核开发过程中最令人生畏的部分。但是,如果你
记住一些事情,生活会变得容易得多:
- 如果你已经很好地解释了你的补丁,评论人员会理解它的价值,以及为什么你会
费尽心思去写它。但是这个并不能阻止他们提出一个基本的问题:五年或十年后
用这个代码维护一个内核会是什么感觉?你可能被要求做出的许多改变——从编码风格
的调整到大量的重写——都来自于对Linux的理解,即从现在起十年后,Linux仍将在
开发中。
- 代码审查是一项艰苦的工作,这是一项相对吃力不讨好的工作;人们记得谁编写了
内核代码,但对于那些审查它的人来说,几乎没有什么持久的名声。因此,评论
人员可能会变得暴躁,尤其是当他们看到同样的错误被一遍又一遍地犯下时。如果
你得到了一个看起来愤怒、侮辱或完全冒犯你的评论,抵制以同样方式回应的冲动。
代码审查是关于代码的,而不是关于人的,代码审查人员不会亲自攻击您。
- 同样,代码审查人员也不想以牺牲你雇主的利益为代价来宣传他们雇主的议程。
内核开发人员通常希望今后几年能在内核上工作,但他们明白他们的雇主可能会改
变。他们真的,几乎毫无例外地,致力于创造他们所能做到的最好的内核;他们并
没有试图给雇主的竞争对手造成不适。
所有这些归根结底都是,当审阅者向您发送评论时,您需要注意他们正在进行的技术
观察。不要让他们的表达方式或你自己的骄傲阻止这种事情的发生。当你在一个补丁
上得到评论时,花点时间去理解评论人想说什么。如果可能的话,请修复审阅者要求
您修复的内容。然后回复审稿人:谢谢他们,并描述你将如何回答他们的问题。
请注意,您不必同意审阅者建议的每个更改。如果您认为审阅者误解了您的代码,请
解释到底发生了什么。如果您对建议的更改有技术上的异议,请描述它并证明您对该
问题的解决方案是正确的。如果你的解释有道理,审稿人会接受的。不过,如果你的
解释不能证明是有说服力的,尤其是当其他人开始同意审稿人的观点时,请花些时间
重新考虑一下。你很容易对自己解决问题的方法视而不见,以至于你没有意识到某个
问题根本是错误的,或者你甚至没有解决正确的问题。
Andrew Morton建议,每一条不会导致代码更改的评论都应该导致额外的代码注释;
这可以帮助未来的评论人员避免出现第一次出现的问题。
一个致命的错误是忽视评论,希望它们会消失。他们不会走的。如果您在没有对之前
收到的注释做出响应的情况下重新发布代码,那么很可能会发现补丁毫无用处。
说到重新发布代码:请记住,审阅者不会记住您上次发布的代码的所有细节。因此,
提醒审查人员以前提出的问题以及您如何处理这些问题总是一个好主意;补丁变更
日志是提供此类信息的好地方。审阅者不必搜索列表档案来熟悉上次所说的内容;
如果您帮助他们开始运行,当他们重新访问您的代码时,他们的心情会更好。
如果你已经试着做正确的事情,但事情仍然没有进展呢?大多数技术上的分歧都可以
通过讨论来解决,但有时人们只需要做出决定。如果你真的认为这个决定对你不利,
你可以试着向更高的权力上诉。在这篇文章中,更高的权力倾向于Andrew Morton。
Andrew在内核开发社区中受i很大的尊重;他经常为似乎被绝望地阻塞事情清障。
尽管如此,对Andrew的呼吁不应轻而易举,也不应在所有其他替代方案都被探索之前
使用。当然,记住,他也可能不同意你的意见。
接下来会发生什么
----------------
如果一个补丁被认为是添加到内核中的一件好事,并且一旦大多数审查问题得到解决,
下一步通常是进入子系统维护人员的树中。工作方式因子系统而异;每个维护人员都
有自己的工作方式。特别是,可能有不止一棵树——一棵树,也许,专门用于计划下一
个合并窗口的补丁,另一棵树用于长期工作。
对于应用于没有明显子系统树(例如内存管理修补程序)的区域的修补程序,默认树
通常以-mm结尾。影响多个子系统的补丁也可以最终通过-mm树。
包含在子系统树中可以提高补丁的可见性。现在,使用该树的其他开发人员将默认获
得补丁。子系统树通常也为Linux提供支持,使其内容对整个开发社区可见。在这一点
上,您很可能会从一组新的审阅者那里得到更多的评论;这些评论需要像上一轮那样
得到回答。
在这一点上也会发生什么,这取决于你的补丁的性质,是与其他人正在做的工作发生
冲突。在最坏的情况下,严重的补丁冲突可能会导致一些工作被搁置,以便剩余的补丁
可以成形并合并。另一些时候,冲突解决将涉及到与其他开发人员合作,可能还会
在树之间移动一些补丁,以确保所有的应用都是干净的。这项工作可能是一件痛苦的
事情,但要计算您的福祉:在Linux下一棵树出现之前,这些冲突通常只在合并窗口
中出现,必须迅速解决。现在可以在合并窗口打开之前,在空闲时解决这些问题。
有朝一日,如果一切顺利,您将登录并看到您的补丁已经合并到主线内核中。祝贺你!
然而,一旦庆祝活动完成(并且您已经将自己添加到维护人员文件中),就值得记住
一个重要的小事实:工作仍然没有完成。并入主线带来了自身的挑战。
首先,补丁的可见性再次提高。可能会有新一轮的开发者评论,他们以前不知道这
个补丁。忽略它们可能很有诱惑力,因为您的代码不再存在任何被合并的问题。但是,
要抵制这种诱惑,您仍然需要对有问题或建议的开发人员作出响应。
不过,更重要的是:将代码包含在主线中会将代码交给更大的一组测试人员。即使您
为尚未提供的硬件提供了驱动程序,您也会惊讶于有多少人会将您的代码构建到内核
中。当然,如果有测试人员,也会有错误报告。
最糟糕的错误报告是回归。如果你的补丁导致回归,你会发现很多不舒服的眼睛盯着
你;回归需要尽快修复。如果您不愿意或无法修复回归(其他人都不会为您修复),
那么在稳定期内,您的补丁几乎肯定会被移除。除了否定您为使补丁进入主线所做的
所有工作之外,如果由于未能修复回归而取消补丁,很可能会使将来的工作更难合并。
在处理完任何回归之后,可能还有其他普通的bug需要处理。稳定期是修复这些错误并
确保代码在主线内核版本中的首次发布尽可能可靠的最好机会。所以,请回答错误
报告,并尽可能解决问题。这就是稳定期的目的;一旦解决了旧补丁的任何问题,就
可以开始创建酷的新补丁。
别忘了,还有其他里程碑也可能会创建bug报告:下一个主线稳定版本,当著名的发行
商选择包含补丁的内核版本时,等等。继续响应这些报告是您工作的基本骄傲。但是,
如果这不是足够的动机,那么也值得考虑的是,开发社区会记住那些在合并后对代码
失去兴趣的开发人员。下一次你发布补丁时,他们会以你以后不会在身边维护它为假
设来评估它。
其他可能发生的事情
------------------
有一天,你可以打开你的邮件客户端,看到有人给你寄了一个代码补丁。毕竟,这是
让您的代码公开存在的好处之一。如果您同意这个补丁,您可以将它转发给子系统
维护人员(确保包含一个正确的From:行,这样属性是正确的,并添加一个您自己
的签准),或者回复一个Acked-by,让原始发送者向上发送它。
如果您不同意补丁,请发送一个礼貌的回复,解释原因。如果可能的话,告诉作者需要
做哪些更改才能让您接受补丁。对于代码的编写者和维护者所反对的合并补丁,存在着
一定的阻力,但仅此而已。如果你被认为不必要的阻碍了好的工作,那么这些补丁最
终会经过你身边并进入主线。在Linux内核中,没有人对任何代码拥有绝对的否决权。
除了Linus。
在非常罕见的情况下,您可能会看到完全不同的东西:另一个开发人员发布了针对您
的问题的不同解决方案。在这一点上,两个补丁中的一个可能不会合并,“我的在这里
是第一个”不被认为是一个令人信服的技术论据。如果有人的补丁取代了你的补丁而进
入了主线,那么只有一种方法可以回应你:高兴你的问题得到解决,继续你的工作。
以这种方式把一个人的工作推到一边可能会伤害和气馁,但是在他们忘记了谁的补丁
真正被合并很久之后,社区会记住你的反应。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/7.AdvancedTopics.rst <development_advancedtopics>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_advancedtopics:
高级主题
========
现在,希望您能够掌握开发流程的工作方式。然而,还有更多的东西要学!本节将介绍
一些主题,这些主题对希望成为Linux内核开发过程常规部分的开发人员有帮助。
使用Git管理补丁
---------------
内核使用分布式版本控制始于2002年初,当时Linus首次开始使用专有的Bitkeeper应用
程序。虽然bitkeeper存在争议,但它所体现的软件版本管理方法却肯定不是。分布式
版本控制可以立即加速内核开发项目。在当前的时代,有几种免费的比特保持器替代品。
无论好坏,内核项目都将Git作为其选择的工具。
使用Git管理补丁可以使开发人员的生活更加轻松,尤其是随着补丁数量的增加。Git
也有其粗糙的边缘和一定的危险,它是一个年轻和强大的工具,仍然在其开发人员完善
中。本文档不会试图教会读者如何使用git;这会是个巨长的文档。相反,这里的重点
将是Git如何特别适合内核开发过程。想要加快Git的开发人员可以在以下网站上找到
更多信息:
http://git-scm.com/
http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
在尝试使用它使补丁可供其他人使用之前,第一要务是阅读上述站点,对Git的工作
方式有一个扎实的了解。使用Git的开发人员应该能够获得主线存储库的副本,探索
修订历史,提交对树的更改,使用分支等。了解Git用于重写历史的工具(如Rebase)
也很有用。Git有自己的术语和概念;Git的新用户应该了解refs、远程分支、索引、
快进合并、推拉、分离头等。一开始可能有点吓人,但这些概念不难通过一点学习来
理解。
使用git生成通过电子邮件提交的补丁是提高速度的一个很好的练习。
当您准备好开始安装Git树供其他人查看时,您当然需要一个可以从中提取的服务器。
如果您有一个可以访问Internet的系统,那么使用git守护进程设置这样的服务器相
对简单。否则,免费的公共托管网站(例如github)开始出现在网络上。成熟的开发
人员可以在kernel.org上获得一个帐户,但这些帐户并不容易找到;有关更多信息,
请参阅 http://kernel.org/faq/
正常的Git工作流程涉及到许多分支的使用。每一条开发线都可以分为单独的“主题
分支”,并独立维护。Git的分支机构很便宜,没有理由不免费使用它们。而且,在
任何情况下,您都不应该在任何您打算让其他人从中受益的分支中进行开发。应该
小心地创建公开可用的分支;当它们处于完整的形式并准备好运行时(而不是之前),
合并开发分支的补丁。
Git提供了一些强大的工具,可以让您重写开发历史。一个不方便的补丁(比如说,
一个打破二分法的补丁,或者有其他一些明显的缺陷)可以在适当的位置修复,或者
完全从历史中消失。一个补丁系列可以被重写,就好像它是在今天的主线之上写的
一样,即使你已经花了几个月的时间在写它。可以透明地将更改从一个分支转移到另
一个分支。等等。明智地使用git修改历史的能力可以帮助创建问题更少的干净补丁集。
然而,过度使用这种能力可能会导致其他问题,而不仅仅是对创建完美项目历史的
简单痴迷。重写历史将重写该历史中包含的更改,将经过测试(希望)的内核树变
为未经测试的内核树。但是,除此之外,如果开发人员没有对项目历史的共享视图,
他们就无法轻松地协作;如果您重写了其他开发人员拉入他们存储库的历史,您将
使这些开发人员的生活更加困难。因此,这里有一个简单的经验法则:被导出到其他
人的历史在此后通常被认为是不可变的。
因此,一旦将一组更改推送到公开可用的服务器上,就不应该重写这些更改。如果您
尝试强制进行不会导致快进合并(即不共享同一历史记录的更改)的更改,Git将尝
试强制执行此规则。可以重写此检查,有时可能需要重写导出的树。在树之间移动变
更集以避免Linux-next中的冲突就是一个例子。但这种行为应该是罕见的。这就是为
什么开发应该在私有分支中进行(必要时可以重写)并且只有在公共分支处于合理的
高级状态时才转移到公共分支中的原因之一。
当主线(或其他一组变更所基于的树)前进时,很容易与该树合并以保持领先地位。
对于一个私有的分支,rebasing 可能是一个很容易跟上另一棵树的方法,但是一旦
一棵树被导出到全世界,rebasing就不是一个选项。一旦发生这种情况,就必须进行
完全合并(merge)。合并有时是很有意义的,但是过于频繁的合并会不必要地扰乱
历史。在这种情况下,建议的技术是不经常合并,通常只在特定的发布点(如主线-rc
发布)合并。如果您对特定的更改感到紧张,则可以始终在私有分支中执行测试合并。
在这种情况下,git rerere 工具很有用;它记住合并冲突是如何解决的,这样您就
不必重复相同的工作。
关于Git这样的工具的一个最大的反复抱怨是:补丁从一个存储库到另一个存储库的
大量移动使得很容易陷入错误建议的变更中,这些变更避开审查雷达进入主线。当内
核开发人员看到这种情况发生时,他们往往会感到不高兴;在Git树上放置未查看或
主题外的补丁可能会影响您将来获取树的能力。引用Linus:
::
你可以给我发补丁,但要我从你哪里取一个Git补丁,我需要知道你知道
你在做什么,我需要能够相信事情而不去检查每个个人改变。
(http://lwn.net/articles/224135/)。
为了避免这种情况,请确保给定分支中的所有补丁都与相关主题紧密相关;“驱动程序
修复”分支不应更改核心内存管理代码。而且,最重要的是,不要使用Git树来绕过
审查过程。不时的将树的摘要发布到相关的列表中,当时间合适时,请求
Linux-next 中包含该树。
如果其他人开始发送补丁以包含到您的树中,不要忘记查看它们。还要确保您维护正确
的作者信息; ``git am`` 工具在这方面做得最好,但是如果它通过第三方转发给您,
您可能需要在补丁中添加“From:”行。
请求pull操作时,请务必提供所有相关信息:树的位置、要拉的分支以及拉操作将导致
的更改。在这方面,git request pull 命令非常有用;它将按照其他开发人员的预期
格式化请求,并检查以确保您记住了将这些更改推送到公共服务器。
审查补丁
--------
一些读者当然会反对将本节与“高级主题”放在一起,因为即使是刚开始的内核开发人员
也应该检查补丁。当然,学习如何在内核环境中编程没有比查看其他人发布的代码更好
的方法了。此外,审阅者永远供不应求;通过查看代码,您可以对整个流程做出重大贡献。
审查代码可能是一个令人生畏的前景,特别是对于一个新的内核开发人员来说,他们
可能会对公开询问代码感到紧张,而这些代码是由那些有更多经验的人发布的。不过,
即使是最有经验的开发人员编写的代码也可以得到改进。也许对评审员(所有评审员)
最好的建议是:把评审评论当成问题而不是批评。询问“在这条路径中如何释放锁?”
总是比说“这里的锁是错误的”更好。
不同的开发人员将从不同的角度审查代码。一些主要关注的是编码样式以及代码行是
否有尾随空格。其他人将主要关注补丁作为一个整体实现的变更是否对内核有好处。
然而,其他人会检查是否存在锁定问题、堆栈使用过度、可能的安全问题、在其他
地方发现的代码重复、足够的文档、对性能的不利影响、用户空间ABI更改等。所有
类型的检查,如果它们导致更好的代码进入内核,都是受欢迎和值得的。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/8.Conclusion.rst <development_conclusion>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_conclusion:
更多信息
========
关于Linux内核开发和相关主题的信息来源很多。首先是在内核源代码分发中找到的
文档目录。顶级 :ref:`Documentation/translations/zh_CN/process/howto.rst <cn_process_howto>`
文件是一个重要的起点
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
和 :ref:`process/submitting-drivers.rst <submittingdrivers>`
也是所有内核开发人员都应该阅读的内容。许多内部内核API都是使用kerneldoc机制
记录的;“make htmldocs”或“make pdfdocs”可用于以HTML或PDF格式生成这些文档(
尽管某些发行版提供的tex版本会遇到内部限制,无法正确处理文档)。
不同的网站在各个细节层次上讨论内核开发。您的作者想谦虚地建议用 http://lwn.net/
作为来源;有关许多特定内核主题的信息可以通过以下网址的lwn内核索引找到:
http://lwn.net/kernel/index/
除此之外,内核开发人员的一个宝贵资源是:
http://kernelnewbies.org/
当然,我们不应该忘记 http://kernel.org/ 这是内核发布信息的最终位置。
关于内核开发有很多书:
Linux设备驱动程序,第三版(Jonathan Corbet、Alessandro Rubini和Greg Kroah Hartman)。
在线:http://lwn.net/kernel/ldd3/
Linux内核开发(Robert Love)。
了解Linux内核(Daniel Bovet和Marco Cesati)。
然而,所有这些书都有一个共同的缺点:当它们上架时,它们往往有些过时,而且它们
已经上架一段时间了。不过,在那里还可以找到相当多的好信息。
有关git的文档,请访问:
http://www.kernel.org/pub/software/scm/git/docs/
http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
结论
====
祝贺所有通过这篇冗长的文件的人。希望它能够帮助您理解Linux内核是如何开发的,
以及您如何参与这个过程。
最后,重要的是参与。任何开源软件项目都不超过其贡献者投入其中的总和。Linux内核
的发展速度和以前一样快,因为它得到了大量开发人员的帮助,他们都在努力使它变得
更好。内核是一个主要的例子,说明当成千上万的人为了一个共同的目标一起工作时,
可以做些什么。
不过,内核总是可以从更大的开发人员基础中获益。总有更多的工作要做。但是,同样
重要的是,Linux生态系统中的大多数其他参与者可以通过为内核做出贡献而受益。使
代码进入主线是提高代码质量、降低维护和分发成本、提高对内核开发方向的影响程度
等的关键。这是一种人人都赢的局面。踢开你的编辑,来加入我们吧,你会非常受
欢迎的。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/code-of-conduct-interpretation.rst <code_of_conduct_interpretation>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_code_of_conduct_interpretation:
Linux内核贡献者契约行为准则解释
===============================
:ref:`cn_code_of_conduct` 准则是一个通用文档,旨在为几乎所有开源社区提供一套规则。
每个开源社区都是独一无二的,Linux内核也不例外。因此,本文描述了Linux内核社区中
如何解释它。我们也不希望这种解释随着时间的推移是静态的,并将根据需要进行调整。
与开发软件的“传统”方法相比,Linux内核开发工作是一个非常个人化的过程。你的贡献
和背后的想法将被仔细审查,往往导致批判和批评。审查将几乎总是需要改进,材料才
能包括在内核中。要知道这是因为所有相关人员都希望看到Linux整体成功的最佳解决方
案。这个开发过程已经被证明可以创建有史以来最健壮的操作系统内核,我们不想做任何
事情来导致提交质量和最终结果的下降。
维护者
------
行为准则多次使用“维护者”一词。在内核社区中,“维护者”是负责子系统、驱动程序或
文件的任何人,并在内核源代码树的维护者文件中列出。
责任
----
《行为准则》提到了维护人员的权利和责任,这需要进一步澄清。
首先,最重要的是,有一个合理的期望是由维护人员通过实例来领导。
也就是说,我们的社区是广阔的,对维护者没有新的要求,他们单方面处理其他人在
他们活跃的社区的行为。这一责任由我们所有人承担,最终《行为准则》记录了最终的
上诉路径,以防有关行为问题的问题悬而未决。
维护人员应该愿意在出现问题时提供帮助,并在需要时与社区中的其他人合作。如果您
不确定如何处理出现的情况,请不要害怕联系技术咨询委员会(TAB)或其他维护人员。
除非您愿意,否则不会将其视为违规报告。如果您不确定是否该联系TAB 或任何其他维
护人员,请联系我们的冲突调解人 Mishi Choudhary <mishi@linux.com>。
最后,“善待对方”才是每个人的最终目标。我们知道每个人都是人,有时我们都会失败,
但我们所有人的首要目标应该是努力友好地解决问题。执行行为准则将是最后的选择。
我们的目标是创建一个强大的、技术先进的操作系统,以及所涉及的技术复杂性,这自
然需要专业知识和决策。
所需的专业知识因贡献领域而异。它主要由上下文和技术复杂性决定,其次由贡献者和
维护者的期望决定。
专家的期望和决策都要经过讨论,但在最后,为了取得进展,必须能够做出决策。这一
特权掌握在维护人员和项目领导的手中,预计将善意使用。
因此,设定专业知识期望、作出决定和拒绝不适当的贡献不被视为违反行为准则。
虽然维护人员一般都欢迎新来者,但他们帮助(新)贡献者克服障碍的能力有限,因此
他们必须确定优先事项。这也不应被视为违反了行为准则。内核社区意识到这一点,并
以各种形式提供入门级节目,如 kernelnewbies.org 。
范围
----
Linux内核社区主要在一组公共电子邮件列表上进行交互,这些列表分布在由多个不同
公司或个人控制的多个不同服务器上。所有这些列表都在内核源代码树中的
MAINTAINERS 文件中定义。发送到这些邮件列表的任何电子邮件都被视为包含在行为
准则中。
使用 kernel.org bugzilla和其他子系统bugzilla 或bug跟踪工具的开发人员应该遵循
行为准则的指导原则。Linux内核社区没有“官方”项目电子邮件地址或“官方”社交媒体
地址。使用kernel.org电子邮件帐户执行的任何活动必须遵循为kernel.org发布的行为
准则,就像任何使用公司电子邮件帐户的个人必须遵循该公司的特定规则一样。
行为准则并不禁止在邮件列表消息、内核更改日志消息或代码注释中继续包含名称、
电子邮件地址和相关注释。
其他论坛中的互动包括在适用于上述论坛的任何规则中,通常不包括在行为准则中。
除了在极端情况下可考虑的例外情况。
提交给内核的贡献应该使用适当的语言。在行为准则之前已经存在的内容现在不会被
视为违反。然而,不适当的语言可以被视为一个bug;如果任何相关方提交补丁,
这样的bug将被更快地修复。当前属于用户/内核API的一部分的表达式,或者反映已
发布标准或规范中使用的术语的表达式,不被视为bug。
执行
----
行为准则中列出的地址属于行为准则委员会。https://kernel.org/code-of-conduct.html
列出了在任何给定时间接收这些电子邮件的确切成员。成员不能访问在加入委员会之前
或离开委员会之后所做的报告。
最初的行为准则委员会由TAB的志愿者以及作为中立第三方的专业调解人组成。委员会
的首要任务是建立文件化的流程,并将其公开。
如果报告人不希望将整个委员会纳入投诉或关切,可直接联系委员会的任何成员,包括
调解人。
行为准则委员会根据流程审查案例(见上文),并根据需要和适当与TAB协商,例如请求
和接收有关内核社区的信息。
委员会做出的任何决定都将提交到表中,以便在必要时与相关维护人员一起执行。行为
准则委员会的决定可以通过三分之二的投票推翻。
每季度,行为准则委员会和标签将提供一份报告,概述行为准则委员会收到的匿名报告
及其状态,以及任何否决决定的细节,包括完整和可识别的投票细节。
我们希望在启动期之后为行为准则委员会人员配备建立一个不同的流程。发生此情况时,
将使用该信息更新此文档。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/code-of-conduct.rst <code_of_conduct>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_code_of_conduct:
贡献者契约行为准则
++++++++++++++++++
我们的誓言
==========
为了营造一个开放、友好的环境,我们作为贡献者和维护人承诺,让我们的社区和参
与者,拥有一个无骚扰的体验,无论年龄、体型、残疾、种族、性别特征、性别认同
和表达、经验水平、教育程度、社会状况,经济地位、国籍、个人外貌、种族、宗教
或性身份和取向。
我们的标准
==========
有助于创造积极环境的行为包括:
* 使用欢迎和包容的语言
* 尊重不同的观点和经验
* 优雅地接受建设性的批评
* 关注什么对社区最有利
* 对其他社区成员表示同情
参与者的不可接受行为包括:
* 使用性意味的语言或意象以及不受欢迎的性注意或者更过分的行为
* 煽动、侮辱/贬损评论以及个人或政治攻击
* 公开或私下骚扰
* 未经明确许可,发布他人的私人信息,如物理或电子地址。
* 在专业场合被合理认为不适当的其他行为
我们的责任
==========
维护人员负责澄清可接受行为的标准,并应针对任何不可接受行为采取适当和公平的
纠正措施。
维护人员有权和责任删除、编辑或拒绝与本行为准则不一致的评论、承诺、代码、
wiki编辑、问题和其他贡献,或暂时或永久禁止任何贡献者从事他们认为不适当、
威胁、冒犯或有害的其他行为。
范围
====
当个人代表项目或其社区时,本行为准则既适用于项目空间,也适用于公共空间。
代表一个项目或社区的例子包括使用一个正式的项目电子邮件地址,通过一个正式
的社交媒体帐户发布,或者在在线或离线事件中担任指定的代表。项目维护人员可以
进一步定义和澄清项目的表示。
执行
====
如有滥用、骚扰或其他不可接受的行为,可联系行为准则委员会<conduct@kernel.org>。
所有投诉都将接受审查和调查,并将得到必要和适当的答复。行为准则委员会有义务
对事件报告人保密。具体执行政策的进一步细节可单独公布。
归属
====
本行为准则改编自《贡献者契约》,版本1.4,可从
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 获取。
解释
====
有关Linux内核社区如何解释此文档,请参阅 :ref:`cn_code_of_conduct_interpretation`
Chinese translated version of Documentation/process/coding-style.rst
.. include:: ../disclaimer-zh_CN.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.
:Original: :ref:`Documentation/process/coding-style.rst <codingstyle>`
Chinese maintainer: Zhang Le <r0bertz@gentoo.org>
.. _cn_codingstyle:
---------------------------------------------------------------------
Documentation/process/coding-style.rst 的中文翻译
如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,
也可以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版
维护者::
译者::
中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org>
中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org>
......@@ -23,10 +14,6 @@ Documentation/process/coding-style.rst 的中文翻译
Li Zefan <lizf@cn.fujitsu.com>
Wang Chen <wangchen@cn.fujitsu.com>
以下为正文
---------------------------------------------------------------------
Linux 内核代码风格
=========================
......
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/development-process.rst <development_process_main>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_development_process_main:
内核开发过程指南
================
内容:
.. toctree::
:numbered:
:maxdepth: 2
1.Intro
2.Process
3.Early-stage
4.Coding
5.Posting
6.Followthrough
7.AdvancedTopics
8.Conclusion
本文档的目的是帮助开发人员(及其经理)以最小的挫折感与开发社区合作。它试图记录这个社区如何以一种不熟悉Linux内核开发(或者实际上是自由软件开发)的人可以访问的方式工作。虽然这里有一些技术资料,但这是一个面向过程的讨论,不需要深入了解内核编程就可以理解。
Chinese translated version of Documentation/process/email-clients.rst
.. _cn_email_clients:
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.
.. include:: ../disclaimer-zh_CN.rst
Chinese maintainer: Harry Wei <harryxiyou@gmail.com>
---------------------------------------------------------------------
Documentation/process/email-clients.rst 的中文翻译
:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
译者::
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版校译者: Yinglin Luan <synmyth@gmail.com>
Xiaochen Wang <wangxiaochen0@gmail.com>
yaxinsn <yaxinsn@163.com>
以下为正文
---------------------------------------------------------------------
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
中文版校译者: Yinglin Luan <synmyth@gmail.com>
Xiaochen Wang <wangxiaochen0@gmail.com>
yaxinsn <yaxinsn@163.com>
Linux邮件客户端配置信息
======================================================================
=======================
Git
---
现在大多数开发人员使用 ``git send-email`` 而不是常规的电子邮件客户端。这方面
的手册非常好。在接收端,维护人员使用 ``git am`` 加载补丁。
如果你是 ``git`` 新手,那么把你的第一个补丁发送给你自己。将其保存为包含所有
标题的原始文本。运行 ``git am raw_email.txt`` ,然后使用 ``git log`` 查看更
改日志。如果工作正常,再将补丁发送到相应的邮件列表。
普通配置
----------------------------------------------------------------------
--------
Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的内嵌文本。有些维护者
接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的,
因为这会使补丁的引用部分在评论过程中变的很困难。
......@@ -56,7 +57,7 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
一些邮件客户端提示
----------------------------------------------------------------------
------------------
这里给出一些详细的MUA配置提示,可以用于给Linux内核发送补丁。这些并不意味是
所有的软件包配置总结。
......@@ -64,8 +65,8 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
TUI = 以文本为基础的用户接口
GUI = 图形界面用户接口
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Alpine (TUI)
~~~~~~~~~~~~
配置选项:
在"Sending Preferences"部分:
......@@ -76,8 +77,8 @@ Alpine (TUI)
当写邮件时,光标应该放在补丁会出现的地方,然后按下CTRL-R组合键,使指定的
补丁文件嵌入到邮件中。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Evolution (GUI)
~~~~~~~~~~~~~~~
一些开发者成功的使用它发送补丁
......@@ -89,8 +90,8 @@ Evolution (GUI)
你还可以"diff -Nru old.c new.c | xclip",选择Preformat,然后使用中间键进行粘帖。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kmail (GUI)
~~~~~~~~~~~
一些开发者成功的使用它发送补丁。
......@@ -118,13 +119,13 @@ display",这样内嵌附件更容易让读者看到。
并且希望这将会被处理。邮件是以只针对某个用户可读写的权限被保存的,所以如果你想把邮件复制到其他地方,
你不得不把他们的权限改为组或者整体可读。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lotus Notes (GUI)
~~~~~~~~~~~~~~~~~
不要使用它。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mutt (TUI)
~~~~~~~~~~
很多Linux开发人员使用mutt客户端,所以证明它肯定工作的非常漂亮。
......@@ -142,12 +143,49 @@ Mutt不自带编辑器,所以不管你使用什么编辑器都不应该带有
如果想要把补丁作为内嵌文本。
(a)ttach工作的很好,不带有"set paste"。
你可以通过 ``git format-patch`` 生成补丁,然后用 Mutt发送它们::
$ mutt -H 0001-some-bug-fix.patch
配置选项:
它应该以默认设置的形式工作。
然而,把"send_charset"设置为"us-ascii::utf-8"也是一个不错的主意。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置::
# .muttrc
# ================ IMAP ====================
set imap_user = 'yourusername@gmail.com'
set imap_pass = 'yourpassword'
set spoolfile = imaps://imap.gmail.com/INBOX
set folder = imaps://imap.gmail.com/
set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"
# ================ SMTP ====================
set smtp_url = "smtp://username@smtp.gmail.com:587/"
set smtp_pass = $imap_pass
set ssl_force_tls = yes # Require encrypted connection
# ================ Composition ====================
set editor = `echo \$EDITOR`
set edit_headers = yes # See the headers when editing
set charset = UTF-8 # value of $LANG; also fallback for send_charset
# Sender, email address, and sign-off line must match
unset use_domain # because joe@localhost is just embarrassing
set realname = "YOUR NAME"
set from = "username@gmail.com"
set use_from = yes
Mutt文档含有更多信息:
http://dev.mutt.org/trac/wiki/UseCases/Gmail
http://dev.mutt.org/doc/manual.html
Pine (TUI)
~~~~~~~~~~
Pine过去有一些空格删减问题,但是这些现在应该都被修复了。
......@@ -158,8 +196,8 @@ Pine过去有一些空格删减问题,但是这些现在应该都被修复了
- "no-strip-whitespace-before-send"选项也是需要的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sylpheed (GUI)
~~~~~~~~~~~~~~
- 内嵌文本可以很好的工作(或者使用附件)。
- 允许使用外部的编辑器。
......@@ -168,8 +206,8 @@ Sylpheed (GUI)
- 在组成窗口中有一个很有用的ruler bar。
- 给地址本中添加地址就不会正确的了解显示名。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Thunderbird (GUI)
~~~~~~~~~~~~~~~~~
默认情况下,thunderbird很容易损坏文本,但是还有一些方法可以强制它变得更好。
......@@ -191,13 +229,13 @@ Thunderbird (GUI)
$EDITOR来读取或者合并补丁到文本中。要实现它,可以下载并且安装这个扩展,然后添加一个使用它的
按键View->Toolbars->Customize...最后当你书写信息的时候仅仅点击它就可以了。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TkRat (GUI)
~~~~~~~~~~~
可以使用它。使用"Insert file..."或者外部的编辑器。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Gmail (Web GUI)
~~~~~~~~~~~~~~~
不要使用它发送补丁。
......
Chinese translated version of Documentation/process/howto.rst
.. _cn_process_howto:
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
.. include:: ../disclaimer-zh_CN.rst
Maintainer: Greg Kroah-Hartman <greg@kroah.com>
Chinese maintainer: Li Yang <leoli@freescale.com>
---------------------------------------------------------------------
Documentation/process/howto.rst 的中文翻译
:Original: :ref:`Documentation/process/howto.rst <process_howto>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
译者::
英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 李阳 Li Yang <leoli@freescale.com>
中文版翻译者: 李阳 Li Yang <leoli@freescale.com>
中文版校译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
以下为正文
---------------------------------------------------------------------
英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com>
中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com>
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
中文版校译者:
钟宇 TripleX Chung <xxx.phy@gmail.com>
陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
如何参与Linux内核开发
---------------------
=====================
这是一篇将如何参与Linux内核开发的相关问题一网打尽的终极秘笈。它将指导你
成为一名Linux内核开发者,并且学会如何同Linux内核开发社区合作。它尽可能不
......@@ -47,6 +37,7 @@ Linux内核大部分是由C语言写成的,一些体系结构相关的代码
参与内核开发,你必须精通C语言。除非你想为某个架构开发底层代码,否则你并
不需要了解(任何体系结构的)汇编语言。下面列举的书籍虽然不能替代扎实的C
语言教育和多年的开发经验,但如果需要的话,做为参考还是不错的:
- "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
《C程序设计语言(第2版·新版)》(徐宝文 李志 译)[机械工业出版社]
- "Practical C Programming" by Steve Oualline [O'Reilly]
......@@ -71,9 +62,11 @@ Linux内核使用GNU C和GNU工具链开发。虽然它遵循ISO C89标准,但
--------
Linux内核源代码都是在GPL(通用公共许可证)的保护下发布的。要了解这种许可
的细节请查看源代码主目录下的COPYING文件。如果你对它还有更深入问题请联系
律师,而不要在Linux内核邮件组上提问。因为邮件组里的人并不是律师,不要期
望他们的话有法律效力。
的细节请查看源代码主目录下的COPYING文件。Linux内核许可准则和如何使用
`SPDX <https://spdx.org/>` 标志符说明在这个文件中
:ref:`Documentation/translations/zh_CN/process/license-rules.rst <cn_kernel_licensing>`
如果你对它还有更深入问题请联系律师,而不要在Linux内核邮件组上提问。因为
邮件组里的人并不是律师,不要期望他们的话有法律效力。
对于GPL的常见问题和解答,请访问以下链接:
http://www.gnu.org/licenses/gpl-faq.html
......@@ -89,65 +82,75 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
的维护者解释这些变化。
以下是内核代码中需要阅读的文档:
README
:ref:`Documentation/admin-guide/README.rst <readme>`
文件简要介绍了Linux内核的背景,并且描述了如何配置和编译内核。内核的
新用户应该从这里开始。
Documentation/process/changes.rst
:ref:`Documentation/process/changes.rst <changes>`
文件给出了用来编译和使用内核所需要的最小软件包列表。
Documentation/process/coding-style.rst
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
描述Linux内核的代码风格和理由。所有新代码需要遵守这篇文档中定义的规
范。大多数维护者只会接收符合规定的补丁,很多人也只会帮忙检查符合风格
的代码。
Documentation/process/submitting-patches.rst
Documentation/process/submitting-drivers.rst
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
这两份文档明确描述如何创建和发送补丁,其中包括(但不仅限于):
- 邮件内容
- 邮件格式
- 选择收件人
遵守这些规定并不能保证提交成功(因为所有补丁需要通过严格的内容和风格
审查),但是忽视他们几乎就意味着失败。
其他关于如何正确地生成补丁的优秀文档包括:
"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
:ref:`Documentation/translations/zh_CN/process/stable-api-nonsense.rst <cn_stable_api_nonsense>`
论证内核为什么特意不包括稳定的内核内部API,也就是说不包括像这样的特
性:
- 子系统中间层(为了兼容性?)
- 在不同操作系统间易于移植的驱动程序
- 减缓(甚至阻止)内核代码的快速变化
这篇文档对于理解Linux的开发哲学至关重要。对于将开发平台从其他操作系
统转移到Linux的人来说也很重要。
Documentation/admin-guide/security-bugs.rst
:ref:`Documentation/admin-guide/security-bugs.rst <securitybugs>`
如果你认为自己发现了Linux内核的安全性问题,请根据这篇文档中的步骤来
提醒其他内核开发者并帮助解决这个问题。
Documentation/process/management-style.rst
:ref:`Documentation/translations/zh_CN/process/management-style.rst <cn_managementstyle>`
描述内核维护者的工作方法及其共有特点。这对于刚刚接触内核开发(或者对
它感到好奇)的人来说很重要,因为它解释了很多对于内核维护者独特行为的
普遍误解与迷惑。
Documentation/process/stable-kernel-rules.rst
:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
解释了稳定版内核发布的规则,以及如何将改动放入这些版本的步骤。
Documentation/process/kernel-docs.rst
:ref:`Documentation/process/kernel-docs.rst <kernel_docs>`
有助于内核开发的外部文档列表。如果你在内核自带的文档中没有找到你想找
的内容,可以查看这些文档。
Documentation/process/applying-patches.rst
:ref:`Documentation/process/applying-patches.rst <applying_patches>`
关于补丁是什么以及如何将它打在不同内核开发分支上的好介绍
内核还拥有大量从代码自动生成的文档。它包含内核内部API的全面介绍以及如何
妥善处理加锁的规则。生成的文档会放在 Documentation/DocBook/目录下。在内
核源码的主目录中使用以下不同命令将会分别生成PDF、Postscript、HTML和手册
页等不同格式的文档:
页等不同格式的文档::
make pdfdocs
make htmldocs
......@@ -155,7 +158,9 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
如何成为内核开发者
------------------
如果你对Linux内核开发一无所知,你应该访问“Linux内核新手”计划:
http://kernelnewbies.org
它拥有一个可以问各种最基本的内核开发问题的邮件列表(在提问之前一定要记得
查找已往的邮件,确认是否有人已经回答过相同的问题)。它还拥有一个可以获得
实时反馈的IRC聊天频道,以及大量对于学习Linux内核开发相当有帮助的文档。
......@@ -166,23 +171,21 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
如果你想加入内核开发社区并协助完成一些任务,却找不到从哪里开始,可以访问
“Linux内核房管员”计划:
http://kernelnewbies.org/KernelJanitors
这是极佳的起点。它提供一个相对简单的任务列表,列出内核代码中需要被重新
整理或者改正的地方。通过和负责这个计划的开发者们一同工作,你会学到将补丁
集成进内核的基本原理。如果还没有决定下一步要做什么的话,你还可能会得到方
向性的指点。
如果你已经有一些现成的代码想要放到内核中,但是需要一些帮助来使它们拥有正
确的格式。请访问“内核导师”计划。这个计划就是用来帮助你完成这个目标的。它
是一个邮件列表,地址如下:
http://selenic.com/mailman/listinfo/kernel-mentors
在真正动手修改内核代码之前,理解要修改的代码如何运作是必需的。要达到这个
目的,没什么办法比直接读代码更有效了(大多数花招都会有相应的注释),而且
一些特制的工具还可以提供帮助。例如,“Linux代码交叉引用”项目就是一个值得
特别推荐的帮助工具,它将源代码显示在有编目和索引的网页上。其中一个更新及
时的内核源码库,可以通过以下地址访问:
http://sosdg.org/~coywolf/lxr/
https://elixir.bootlin.com/
开发流程
......@@ -190,22 +193,23 @@ Linux内核代码中包含有大量的文档。这些文档对于学习如何与
目前Linux内核开发流程包括几个“主内核分支”和很多子系统相关的内核分支。这
些分支包括:
- 2.6.x主内核源码树
- 2.6.x.y -stable内核源码树
- 2.6.x -mm内核补丁集
- 子系统相关的内核源码树和补丁集
- Linus 的内核源码树
- 多个主要版本的稳定版内核树
- 子系统相关的内核树
- linux-next 集成测试树
主线树
------
主线树是由Linus Torvalds 维护的。你可以在https://kernel.org 网站或者代码
库中下找到它。它的开发遵循以下步骤:
2.6.x内核主源码树
-----------------
2.6.x内核是由Linus Torvalds(Linux的创造者)亲自维护的。你可以在
kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循以下步
骤:
- 每当一个新版本的内核被发布,为期两周的集成窗口将被打开。在这段时间里
维护者可以向Linus提交大段的修改,通常这些修改已经被放到-mm内核中几个
星期了。提交大量修改的首选方式是使用git工具(内核的代码版本管理工具
,更多的信息可以在http://git-scm.com/获取),不过使用普通补丁也是可以
的。
,更多的信息可以在 http://git-scm.com/ 获取),不过使用普通补丁也是
可以的。
- 两个星期以后-rc1版本内核发布。之后只有不包含可能影响整个内核稳定性的
新功能的补丁才可能被接受。请注意一个全新的驱动程序(或者文件系统)有
可能在-rc1后被接受是因为这样的修改完全独立,不会影响其他的代码,所以
......@@ -220,106 +224,61 @@ kernel.org网站的pub/linux/kernel/v2.6/目录下找到它。它的开发遵循
“没有人知道新内核何时会被发布,因为发布是根据已知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文件具体描述了可被稳定
版内核接受的修改类型以及发布的流程。
各种内核子系统的维护者——以及许多内核子系统开发人员——在源代码库中公开了他们
当前的开发状态。这样,其他人就可以看到内核的不同区域发生了什么。在开发速度
很快的领域,可能会要求开发人员将提交的内容建立在这样的子系统内核树上,这样
就避免了提交与其他已经进行的工作之间的冲突。
这些存储库中的大多数都是Git树,但是也有其他的scm在使用,或者补丁队列被发布
为Quilt系列。这些子系统存储库的地址列在MAINTAINERS文件中。其中许多可以在
https://git.kernel.org/上浏览。
2.6.x -mm补丁集
---------------
这是由Andrew Morton维护的试验性内核补丁集。Andrew将所有子系统的内核源码
和补丁拼凑到一起,并且加入了大量从linux-kernel邮件列表中采集的补丁。这个
源码树是新功能和补丁的试炼场。当补丁在-mm补丁集里证明了其价值以后Andrew
或者相应子系统的维护者会将补丁发给Linus以便集成进主内核源码树。
在将一个建议的补丁提交到这样的子系统树之前,需要对它进行审查,审查主要发生
在邮件列表上(请参见下面相应的部分)。对于几个内核子系统,这个审查过程是通
过工具补丁跟踪的。Patchwork提供了一个Web界面,显示补丁发布、对补丁的任何评
论或修订,维护人员可以将补丁标记为正在审查、接受或拒绝。大多数补丁网站都列
在 https://patchwork.kernel.org/
在将所有新补丁发给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
Linux-next 集成测试树
---------------------
- 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
https://git.kernel.org/?p=linux/kernel/git/next/linux-next.git
- libata开发源码树, Jeff Garzik <jgarzik@pobox.com>
git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
通过这种方式,Linux-next 对下一个合并阶段将进入主线内核的内容给出了一个概要
展望。非常欢冒险的测试者运行测试Linux-next。
- 网络驱动程序开发源码树, Jeff Garzik <jgarzik@pobox.com>
git.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6.git
多个主要版本的稳定版内核树
-----------------------------------
由3个数字组成的内核版本号说明此内核是-stable版本。它们包含内核的相对较小且
至关重要的修补,这些修补针对安全性问题或者严重的内核退步。
- 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
稳定版内核树版本由“稳定版”小组(邮件地址<stable@vger.kernel.org>)维护,一般
隔周发布新版本。
使用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/
内核源码中的 :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
文件具体描述了可被稳定版内核接受的修改类型以及发布的流程。
其他内核源码树可以在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以及需要提供哪些信息来帮助内核开发者们找到问题的根源。
内核源码主目录中的:ref:`admin-guide/reporting-bugs.rst <reportingbugs>`
文件里有一个很好的模板。它指导用户如何报告可能的内核bug以及需要提供哪些信息
来帮助内核开发者们找到问题的根源。
利用bug报告
......@@ -330,12 +289,7 @@ bugzilla.kernel.org是Linux内核开发者们用来跟踪内核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
要尝试修改已知的bug,请访问 http://bugzilla.kernel.org 网址。
邮件列表
......@@ -343,10 +297,14 @@ bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。
正如上面的文档所描述,大多数的骨干内核开发者都加入了Linux Kernel邮件列
表。如何订阅和退订列表的细节可以在这里找到:
http://vger.kernel.org/vger-lists.html#linux-kernel
网上很多地方都有这个邮件列表的存档(archive)。可以使用搜索引擎来找到这些
存档。比如:
http://dir.gmane.org/gmane.linux.kernel
在发信之前,我们强烈建议你先在存档中搜索你想要讨论的问题。很多已经被详细
讨论过的问题只在邮件列表的存档中可以找到。
......@@ -354,10 +312,12 @@ bugzilla.kernel.org是Linux内核开发者们用来跟踪内核Bug的网站。
MAINTAINERS文件中可以找到不同话题对应的邮件列表。
很多邮件列表架设在kernel.org服务器上。这些列表的信息可以在这里找到:
http://vger.kernel.org/vger-lists.html
在使用这些邮件列表时,请记住保持良好的行为习惯。下面的链接提供了与这些列
表(或任何其它邮件列表)交流的一些简单规则,虽然内容有点滥竽充数。
http://www.albion.com/netiquette/
当有很多人回复你的邮件时,邮件的抄送列表会变得很长。请不要将任何人从抄送
......@@ -369,11 +329,12 @@ MAINTAINERS文件中可以找到不同话题对应的邮件列表。
这几行。将你的评论加在被引用的段落之间而不要放在邮件的顶部。
如果你在邮件中附带补丁,请确认它们是可以直接阅读的纯文本(如
Documentation/process/submitting-patches.rst文档中所述)。内核开发者们不希望遇到附件
或者被压缩了的补丁。只有这样才能保证他们可以直接评论你的每行代码。请确保
你使用的邮件发送程序不会修改空格和制表符。一个防范性的测试方法是先将邮件
发送给自己,然后自己尝试是否可以顺利地打上收到的补丁。如果测试不成功,请
调整或者更换你的邮件发送程序直到它正确工作为止。
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
文档中所述)。内核开发者们不希望遇到附件或者被压缩了的补丁。只有这样才能
保证他们可以直接评论你的每行代码。请确保你使用的邮件发送程序不会修改空格
和制表符。一个防范性的测试方法是先将邮件发送给自己,然后自己尝试是否可以
顺利地打上收到的补丁。如果测试不成功,请调整或者更换你的邮件发送程序直到
它正确工作为止。
总而言之,请尊重其他的邮件列表订阅者。
......@@ -383,6 +344,7 @@ Documentation/process/submitting-patches.rst文档中所述)。内核开发者
内核社区的目标就是提供尽善尽美的内核。所以当你提交补丁期望被接受进内核的
时候,它的技术价值以及其他方面都将被评审。那么你可能会得到什么呢?
- 批评
- 评论
- 要求修改
......@@ -395,6 +357,7 @@ Documentation/process/submitting-patches.rst文档中所述)。内核开发者
没在茫茫信海中。
你不应该做的事情:
- 期望自己的补丁不受任何质疑就直接被接受
- 翻脸
- 忽略别人的评论
......@@ -414,7 +377,8 @@ Documentation/process/submitting-patches.rst文档中所述)。内核开发者
内核社区的工作模式同大多数传统公司开发队伍的工作模式并不相同。下面这些例
子,可以帮助你避免某些可能发生问题:
用这些话介绍你的修改提案会有好处:
用这些话介绍你的修改提案会有好处:
- 它同时解决了多个问题
- 它删除了2000行代码
- 这是补丁,它已经解释了我想要说明的
......@@ -422,7 +386,8 @@ Documentation/process/submitting-patches.rst文档中所述)。内核开发者
- 这是一系列小补丁用来……
- 这个修改提高了普通机器的性能……
应该避免如下的说法:
应该避免如下的说法:
- 我们在AIX/ptx/Solaris就是这么做的,所以这么做肯定是好的……
- 我做这行已经20年了,所以……
- 为了我们公司赚钱考虑必须这么做
......@@ -495,6 +460,7 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当
当你发送补丁的时候,需要特别留意邮件正文的内容。因为这里的信息将会做为补
丁的修改记录(ChangeLog),会被一直保留以备大家查阅。它需要完全地描述补丁,
包括:
- 为什么需要这个修改
- 补丁的总体设计
- 实现细节
......@@ -510,7 +476,8 @@ Linux内核社区并不喜欢一下接收大段的代码。修改需要被恰当
很多人已经做到了,而他们都曾经和现在的你站在同样的起点上。
---------------
感谢
----
感谢Paolo Ciarrocchi允许“开发流程”部分基于他所写的文章
(http://www.kerneltravel.net/newbie/2.6-development_process),感谢Randy
Dunlap和Gerrit Huizenga完善了应该说和不该说的列表。感谢Pat Mochel, Hanna
......
.. raw:: latex
\renewcommand\thesection*
\renewcommand\thesubsection*
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/index.rst <process_index>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_process_index:
与Linux 内核社区一起工作
========================
那么你想成为Linux内核开发人员? 欢迎! 不但从技术意义上讲有很多关于内核的知识
需要学,而且了解我们社区的工作方式也很重要。 阅读这些文章可以让您以更轻松地,
麻烦最少的方式将更改合并到内核。
以下是每位开发人员应阅读的基本指南。
.. toctree::
:maxdepth: 1
howto
code-of-conduct
code-of-conduct-interpretation
submitting-patches
programming-language
coding-style
development-process
email-clients
license-rules
其它大多数开发人员感兴趣的社区指南:
.. toctree::
:maxdepth: 1
submitting-drivers
submit-checklist
stable-api-nonsense
stable-kernel-rules
management-style
这些是一些总体技术指南,由于缺乏更好的地方,现在已经放在这里
.. toctree::
:maxdepth: 1
magic-number
volatile-considered-harmful
.. only:: subproject and html
目录
====
* :ref:`genindex`
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/license-rules.rst <kernel_licensing>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_kernel_licensing:
Linux内核许可规则
=================
Linux内核根据LICENSES/preferred/GPL-2.0中提供的GNU通用公共许可证版本2
(GPL-2.0)的条款提供,并在LICENSES/exceptions/Linux-syscall-note中显式
描述了例外的系统调用,如COPYING文件中所述。
此文档文件提供了如何对每个源文件进行注释以使其许可证清晰明确的说明。
它不会取代内核的许可证。
内核源代码作为一个整体适用于COPYING文件中描述的许可证,但是单个源文件可以
具有不同的与GPL-20兼容的许可证::
GPL-1.0+ : GNU通用公共许可证v1.0或更高版本
GPL-2.0+ : GNU通用公共许可证v2.0或更高版本
LGPL-2.0 : 仅限GNU库通用公共许可证v2
LGPL-2.0+: GNU 库通用公共许可证v2或更高版本
LGPL-2.1 : 仅限GNU宽通用公共许可证v2.1
LGPL-2.1+: GNU宽通用公共许可证v2.1或更高版本
除此之外,个人文件可以在双重许可下提供,例如一个兼容的GPL变体,或者BSD,
MIT等许可。
用户空间API(UAPI)头文件描述了用户空间程序与内核的接口,这是一种特殊情况。
根据内核COPYING文件中的注释,syscall接口是一个明确的边界,它不会将GPL要求
扩展到任何使用它与内核通信的软件。由于UAPI头文件必须包含在创建在Linux内核
上运行的可执行文件的任何源文件中,因此此例外必须记录在特别的许可证表述中。
表达源文件许可证的常用方法是将匹配的样板文本添加到文件的顶部注释中。由于
格式,拼写错误等,这些“样板”很难通过那些在上下文中使用的验证许可证合规性
的工具。
样板文本的替代方法是在每个源文件中使用软件包数据交换(SPDX)许可证标识符。
SPDX许可证标识符是机器可解析的,并且是用于提供文件内容的许可证的精确缩写。
SPDX许可证标识符由Linux 基金会的SPDX 工作组管理,并得到了整个行业,工具
供应商和法律团队的合作伙伴的一致同意。有关详细信息,请参阅
https://spdx.org/
Linux内核需要所有源文件中的精确SPDX标识符。内核中使用的有效标识符在
`许可标识符`_ 一节中进行了解释,并且已可以在
https://spdx.org/licenses/ 上的官方SPDX许可证列表中检索,并附带许可证
文本。
许可标识符语法
--------------
1.安置:
   内核文件中的SPDX许可证标识符应添加到可包含注释的文件中的第一行。对于大多
数文件,这是第一行,除了那些在第一行中需要'#!PATH_TO_INTERPRETER'的脚本。
对于这些脚本,SPDX标识符进入第二行。
|
2. 风格:
SPDX许可证标识符以注释的形式添加。注释样式取决于文件类型::
C source: // SPDX-License-Identifier: <SPDX License Expression>
C header: /* SPDX-License-Identifier: <SPDX License Expression> */
ASM: /* SPDX-License-Identifier: <SPDX License Expression> */
scripts: # SPDX-License-Identifier: <SPDX License Expression>
.rst: .. SPDX-License-Identifier: <SPDX License Expression>
.dts{i}: // SPDX-License-Identifier: <SPDX License Expression>
如果特定工具无法处理标准注释样式,则应使用工具接受的相应注释机制。这是在
C 头文件中使用“/\*\*/”样式注释的原因。过去在使用生成的.lds文件中观察到
构建被破坏,其中'ld'无法解析C++注释。现在已经解决了这个问题,但仍然有较
旧的汇编程序工具无法处理C++样式的注释。
|
3. 句法:
<SPDX许可证表达式>是SPDX许可证列表中的SPDX短格式许可证标识符,或者在许可
证例外适用时由“WITH”分隔的两个SPDX短格式许可证标识符的组合。当应用多个许
可证时,表达式由分隔子表达式的关键字“AND”,“OR”组成,并由“(”,“)”包围。
带有“或更高”选项的[L]GPL等许可证的许可证标识符通过使用“+”来表示“或更高”
选项来构建。::
// SPDX-License-Identifier: GPL-2.0+
// SPDX-License-Identifier: LGPL-2.1+
当需要修正的许可证时,应使用WITH。 例如,linux内核UAPI文件使用表达式::
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
// SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note
其它在内核中使用WITH例外的事例如下::
// SPDX-License-Identifier: GPL-2.0 WITH mif-exception
// SPDX-License-Identifier: GPL-2.0+ WITH GCC-exception-2.0
例外只能与特定的许可证标识符一起使用。有效的许可证标识符列在异常文本文件
的标记中。有关详细信息,请参阅 `许可标识符`_ 一章中的 `例外`_ 。
如果文件是双重许可且只选择一个许可证,则应使用OR。例如,一些dtsi文件在双
许可下可用::
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
内核中双许可文件中许可表达式的示例::
// SPDX-License-Identifier: GPL-2.0 OR MIT
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
// SPDX-License-Identifier: GPL-2.0 OR Apache-2.0
// SPDX-License-Identifier: GPL-2.0 OR MPL-1.1
// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) OR MIT
// SPDX-License-Identifier: GPL-1.0+ OR BSD-3-Clause OR OpenSSL
如果文件具有多个许可证,其条款全部适用于使用该文件,则应使用AND。例如,
如果代码是从另一个项目继承的,并且已经授予了将其放入内核的权限,但原始
许可条款需要保持有效::
// SPDX-License-Identifier: (GPL-2.0 WITH Linux-syscall-note) AND MIT
另一个需要遵守两套许可条款的例子是::
// SPDX-License-Identifier: GPL-1.0+ AND LGPL-2.1+
许可标识符
----------
当前使用的许可证以及添加到内核的代码许可证可以分解为:
1. _`优先许可`:
应尽可能使用这些许可证,因为它们已知完全兼容并广泛使用。这些许可证在内核
目录::
LICENSES/preferred/
此目录中的文件包含完整的许可证文本和 `元标记`_ 。文件名与SPDX许可证标识
符相同,后者应用于源文件中的许可证。
例如::
LICENSES/preferred/GPL-2.0
包含GPLv2许可证文本和所需的元标签::
LICENSES/preferred/MIT
包含MIT许可证文本和所需的元标记
_`元标记`:
许可证文件中必须包含以下元标记:
- Valid-License-Identifier:
  一行或多行, 声明那些许可标识符在项目内有效, 以引用此特定许可的文本。通
常这是一个有效的标识符,但是例如对于带有'或更高'选项的许可证,两个标识
符都有效。
- SPDX-URL:
SPDX页面的URL,其中包含与许可证相关的其他信息.
- Usage-Guidance:
使用建议的自由格式文本。该文本必须包含SPDX许可证标识符的正确示例,因为
它们应根据 `许可标识符语法`_ 指南放入源文件中。
- License-Text:
此标记之后的所有文本都被视为原始许可文本
文件格式示例::
Valid-License-Identifier: GPL-2.0
Valid-License-Identifier: GPL-2.0+
SPDX-URL: https://spdx.org/licenses/GPL-2.0.html
Usage-Guide:
To use this license in source code, put one of the following SPDX
tag/value pairs into a comment according to the placement
guidelines in the licensing rules documentation.
For 'GNU General Public License (GPL) version 2 only' use:
SPDX-License-Identifier: GPL-2.0
For 'GNU General Public License (GPL) version 2 or any later version' use:
SPDX-License-Identifier: GPL-2.0+
License-Text:
Full license text
::
SPDX-License-Identifier: MIT
SPDX-URL: https://spdx.org/licenses/MIT.html
Usage-Guide:
To use this license in source code, put the following SPDX
tag/value pair into a comment according to the placement
guidelines in the licensing rules documentation.
SPDX-License-Identifier: MIT
License-Text:
Full license text
|
2. 不推荐的许可证:
这些许可证只应用于现有代码或从其他项目导入代码。这些许可证在内核目录::
LICENSES/other/
此目录中的文件包含完整的许可证文本和 `元标记`_ 。文件名与SPDX许可证标识
符相同,后者应用于源文件中的许可证。
例如::
LICENSES/other/ISC
包含国际系统联合许可文本和所需的元标签::
LICENSES/other/ZLib
包含ZLIB许可文本和所需的元标签.
元标签:
“其他”许可证的元标签要求与 `优先许可`_ 的要求相同。
文件格式示例::
Valid-License-Identifier: ISC
SPDX-URL: https://spdx.org/licenses/ISC.html
Usage-Guide:
Usage of this license in the kernel for new code is discouraged
and it should solely be used for importing code from an already
existing project.
To use this license in source code, put the following SPDX
tag/value pair into a comment according to the placement
guidelines in the licensing rules documentation.
SPDX-License-Identifier: ISC
License-Text:
Full license text
|
3. _`例外`:
某些许可证可以修改,并允许原始许可证不具有的某些例外权利。这些例外在
内核目录::
LICENSES/exceptions/
此目录中的文件包含完整的例外文本和所需的 `例外元标记`_ 。
例如::
LICENSES/exceptions/Linux-syscall-note
包含Linux内核的COPYING文件中记录的Linux系统调用例外,该文件用于UAPI
头文件。例如::
LICENSES/exceptions/GCC-exception-2.0
包含GCC'链接例外',它允许独立于其许可证的任何二进制文件与标记有此例外的
文件的编译版本链接。这是从GPL不兼容源代码创建可运行的可执行文件所必需的。
_`例外元标记`:
以下元标记必须在例外文件中可用:
- SPDX-Exception-Identifier:
  一个可与SPDX许可证标识符一起使用的例外标识符。
- SPDX-URL:
SPDX页面的URL,其中包含与例外相关的其他信息。
- SPDX-Licenses:
  以逗号分隔的例外可用的SPDX许可证标识符列表。
- Usage-Guidance:
使用建议的自由格式文本。必须在文本后面加上SPDX许可证标识符的正确示例,
因为它们应根据 `许可标识符语法`_ 指南放入源文件中。
- Exception-Text:
此标记之后的所有文本都被视为原始异常文本
文件格式示例::
SPDX-Exception-Identifier: Linux-syscall-note
SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html
SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+
Usage-Guidance:
This exception is used together with one of the above SPDX-Licenses
to mark user-space API (uapi) header files so they can be included
into non GPL compliant user-space application code.
To use this exception add it with the keyword WITH to one of the
identifiers in the SPDX-Licenses tag:
SPDX-License-Identifier: <SPDX-License> WITH Linux-syscall-note
Exception-Text:
Full exception text
::
SPDX-Exception-Identifier: GCC-exception-2.0
SPDX-URL: https://spdx.org/licenses/GCC-exception-2.0.html
SPDX-Licenses: GPL-2.0, GPL-2.0+
Usage-Guidance:
The "GCC Runtime Library exception 2.0" is used together with one
of the above SPDX-Licenses for code imported from the GCC runtime
library.
To use this exception add it with the keyword WITH to one of the
identifiers in the SPDX-Licenses tag:
SPDX-License-Identifier: <SPDX-License> WITH GCC-exception-2.0
Exception-Text:
Full exception text
所有SPDX许可证标识符和例外都必须在LICENSES子目录中具有相应的文件。这是允许
工具验证(例如checkpatch.pl)以及准备好从源读取和提取许可证所必需的, 这是
各种FOSS组织推荐的,例如 `FSFE REUSE initiative <https://reuse.software/>`_.
_`模块许可`
-----------------
可加载内核模块还需要MODULE_LICENSE()标记。此标记既不替代正确的源代码
许可证信息(SPDX-License-Identifier),也不以任何方式表示或确定提供模块
源代码的确切许可证。
此标记的唯一目的是提供足够的信息,该模块是否是自由软件或者是内核模块加
载器和用户空间工具的专有模块。
MODULE_LICENSE()的有效许可证字符串是:
============================= =============================================
"GPL" 模块是根据GPL版本2许可的。这并不表示仅限于
GPL-2.0或GPL-2.0或更高版本之间的任何区别。
最正确许可证信息只能通过相应源文件中的许可证
信息来确定
"GPL v2" 和"GPL"相同,它的存在是因为历史原因。
"GPL and additional rights" 表示模块源在GPL v2变体和MIT许可下双重许可的
历史变体。请不要在新代码中使用。
"Dual MIT/GPL" 表达该模块在GPL v2变体或MIT许可证选择下双重
许可的正确方式。
"Dual BSD/GPL" 该模块根据GPL v2变体或BSD许可证选择进行双重
许可。 BSD许可证的确切变体只能通过相应源文件
中的许可证信息来确定。
"Dual MPL/GPL" 该模块根据GPL v2变体或Mozilla Public License
(MPL)选项进行双重许可。 MPL许可证的确切变体
只能通过相应的源文件中的许可证信息来确定。
"Proprietary" 该模块属于专有许可。此字符串仅用于专有的第三
方模块,不能用于在内核树中具有源代码的模块。
以这种方式标记的模块在加载时会使用'P'标记污
染内核,并且内核模块加载器拒绝将这些模块链接
到使用EXPORT_SYMBOL_GPL()导出的符号。
============================= =============================================
.. _cn_magicnumbers:
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/magic-number.rst <magicnumbers>`
如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可
以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者::
中文版维护者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版翻译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
中文版校译者: 贾威威 Jia Wei Wei <harryxiyou@gmail.com>
Linux 魔术数
============
这个文件是有关当前使用的魔术值注册表。当你给一个结构添加了一个魔术值,你也应该把这个魔术值添加到这个文件,因为我们最好把用于各种结构的魔术值统一起来。
使用魔术值来保护内核数据结构是一个非常好的主意。这就允许你在运行期检查(a)一个结构是否已经被攻击,或者(b)你已经给一个例行程序通过了一个错误的结构。后一种情况特别地有用---特别是当你通过一个空指针指向结构体的时候。tty源码,例如,经常通过特定驱动使用这种方法并且反复地排列特定方面的结构。
使用魔术值的方法是在结构的开始处声明的,如下::
struct tty_ldisc {
int magic;
...
};
当你以后给内核添加增强功能的时候,请遵守这条规则!这样就会节省数不清的调试时间,特别是一些古怪的情况,例如,数组超出范围并且重新写了超出部分。遵守这个规则,‪这些情况可以被快速地,安全地避免。
Theodore Ts'o
31 Mar 94
给当前的Linux 2.1.55添加魔术表。
Michael Chastain
<mailto:mec@shout.net>
22 Sep 1997
现在应该最新的Linux 2.1.112.因为在特性冻结期间,不能在2.2.x前改变任何东西。这些条目被数域所排序。
Krzysztof G.Baranowski
<mailto: kgb@knm.org.pl>
29 Jul 1998
更新魔术表到Linux 2.5.45。刚好越过特性冻结,但是有可能还会有一些新的魔术值在2.6.x之前融入到内核中。
Petr Baudis
<pasky@ucw.cz>
03 Nov 2002
更新魔术表到Linux 2.5.74。
Fabian Frederick
<ffrederick@users.sourceforge.net>
09 Jul 2003
===================== ================ ======================== ==========================================
魔术数名 数字 结构 文件
===================== ================ ======================== ==========================================
PG_MAGIC 'P' pg_{read,write}_hdr ``include/linux/pg.h``
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 ``fs/coda/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中找到他们。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/management-style.rst <managementstyle>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_managementstyle:
Linux内核管理风格
=================
这是一个简短的文档,描述了Linux内核首选的(或胡编的,取决于您问谁)管理风格。
它的目的是在某种程度上参照 :ref:`process/coding-style.rst <codingstyle>`
主要是为了避免反复回答 [#cnf1]_ 相同(或类似)的问题。
管理风格是非常个人化的,比简单的编码风格规则更难以量化,因此本文档可能与实
际情况有关,也可能与实际情况无关。起初它是一个玩笑,但这并不意味着它可能不
是真的。你得自己决定。
顺便说一句,在谈到“核心管理者”时,主要是技术负责人,而不是在公司内部进行传
统管理的人。如果你签署了采购订单或者对你的团队的预算有任何了解,你几乎肯定
不是一个核心管理者。这些建议可能适用于您,也可能不适用于您。
首先,我建议你购买“高效人的七个习惯”,而不是阅读它。烧了它,这是一个伟大的
象征性姿态。
.. [#cnf1] 本文件并不是通过回答问题,而是通过让提问者痛苦地明白,我们不知道
答案是什么。
不管怎样,这里是:
.. _decisions:
1)决策
-------
每个人都认为管理者做决定,而且决策很重要。决定越大越痛苦,管理者就必须越高级。
这很明显,但事实并非如此。
游戏的名字是 **避免** 做出决定。尤其是,如果有人告诉你“选择(a)或(b),
我们真的需要你来做决定”,你就是陷入麻烦的管理者。你管理的人比你更了解细节,
所以如果他们来找你做技术决策,你完蛋了。你显然没有能力为他们做这个决定。
(推论:如果你管理的人不比你更了解细节,你也会被搞砸,尽管原因完全不同。
也就是说,你的工作是错的,他们应该管理你的才智)
所以游戏的名字是 **避免** 做出决定,至少是那些大而痛苦的决定。做一些小的
和非结果性的决定是很好的,并且使您看起来好像知道自己在做什么,所以内核管理者
需要做的是将那些大的和痛苦的决定变成那些没有人真正关心的小事情。
这有助于认识到一个大的决定和一个小的决定之间的关键区别是你是否可以在事后修正
你的决定。任何决定都可以通过始终确保如果你错了(而且你一定会错),你以后总是
可以通过回溯来弥补损失。突然间,你就要做两个无关紧要的决定,一个是错误的,另
一个是正确的。
人们甚至会认为这是真正的领导能力(咳,胡说,咳)。
因此,避免重大决策的关键在于避免做那些无法挽回的事情。不要被引导到一个你无法
逃离的角落。走投无路的老鼠可能很危险——走投无路的管理者真可怜。
事实证明,由于没有人会愚蠢到让内核管理者承担巨大的财政责任,所以通常很容易
回溯。既然你不可能浪费掉你无法偿还的巨额资金,你唯一可以回溯的就是技术决策,
而回溯很容易:只要告诉大家你是个不称职的傻瓜,说对不起,然后撤销你去年让别
人所做的毫无价值的工作。突然间,你一年前做的决定不在是一个重大的决定,因为
它很容易被推翻。
事实证明,有些人对接受这种方法有困难,原因有两个:
- 承认你是个白痴比看起来更难。我们都喜欢保持形象,在公共场合说你错了有时
确实很难。
- 如果有人告诉你,你去年所做的工作终究是不值得的,那么对那些可怜的低级工
程师来说也是很困难的,虽然实际的 **工作** 很容易删除,但你可能已经不可
挽回地失去了工程师的信任。记住:“不可撤销”是我们一开始就试图避免的,
而你的决定终究是一个重大的决定。
令人欣慰的是,这两个原因都可以通过预先承认你没有任何线索,提前告诉人们你的
决定完全是初步的,而且可能是错误的事情来有效地缓解。你应该始终保留改变主意
的权利,并让人们 **意识** 到这一点。当你 **还没有** 做过真正愚蠢的事情的时
候,承认自己是愚蠢的要容易得多。
然后,当它真的被证明是愚蠢的时候,人们就转动他们的眼珠说“哎呀,下次不要了”。
这种对不称职的先发制人的承认,也可能使真正做这项工作的人也会三思是否值得做。
毕竟,如果他们不确定这是否是一个好主意,你肯定不应该通过向他们保证他们所做
的工作将会进入(内核)鼓励他们。在他们开始一项巨大的努力之前,至少让他们三
思而后行。
记住:他们最好比你更了解细节,而且他们通常认为他们对每件事都有答案。作为一
个管理者,你能做的最好的事情不是灌输自信,而是对他们所做的事情进行健康的批
判性思考。
顺便说一句,另一种避免做出决定的方法是看起来很可怜的抱怨 “我们不能两者兼
得吗?” 相信我,它是有效的。如果不清楚哪种方法更好,他们最终会弄清楚的。
最终的答案可能是两个团队都会因为这种情况而感到沮丧,以至于他们放弃了。
这听起来像是一个失败,但这通常是一个迹象,表明两个项目都有问题,而参与其中
的人不能做决定的原因是他们都是错误的。你最终会闻到玫瑰的味道,你避免了另一
个你本可以搞砸的决定。
2)人
-----
大多数人都是白痴,做一名管理者意味着你必须处理好这件事,也许更重要的是,
**他们** 必须处理好你。
事实证明,虽然很容易纠正技术错误,但不容易纠正人格障碍。你只能和他们的和
你的(人格障碍)共处。
但是,为了做好作为内核管理者的准备,最好记住不要烧掉任何桥梁,不要轰炸任何
无辜的村民,也不要疏远太多的内核开发人员。事实证明,疏远人是相当容易的,而
亲近一个疏远的人是很难的。因此,“疏远”立即属于“不可逆”的范畴,并根据
:ref:`decisions` 成为绝不可以做的事情。
这里只有几个简单的规则:
(1) 不要叫人笨蛋(至少不要在公共场合)
(2) 学习如何在忘记规则(1)时道歉
问题在于 #1 很容易去做,因为你可以用数百万种不同的方式说“你是一个笨蛋” [#cnf2]_
有时甚至没有意识到,而且几乎总是带着一种白热化的信念,认为你是对的。
你越确信自己是对的(让我们面对现实吧,你可以把几乎所有人都称为坏人,而且你
经常是对的),事后道歉就越难。
要解决此问题,您实际上只有两个选项:
- 非常擅长道歉
- 把“爱”均匀地散开,没有人会真正感觉到自己被不公平地瞄准了。让它有足够的
创造性,他们甚至可能会觉得好笑。
选择永远保持礼貌是不存在的。没有人会相信一个如此明显地隐藏了他们真实性格的人。
.. [#cnf2] 保罗·西蒙演唱了“离开爱人的50种方法”,因为坦率地说,“告诉开发者
他们是D*CKHEAD" 的100万种方法都无法确认。但我确信他已经这么想了。
3)人2 - 好人
-------------
虽然大多数人都是白痴,但不幸的是,据此推论你也是白痴,尽管我们都自我感觉良
好,我们比普通人更好(让我们面对现实吧,没有人相信他们是普通人或低于普通人),
我们也应该承认我们不是最锋利的刀,而且会有其他人比你更不像白痴。
有些人对聪明人反应不好。其他人利用它们。
作为内核维护人员,确保您在第二组中。接受他们,因为他们会让你的工作更容易。
特别是,他们能够为你做决定,这就是游戏的全部内容。
所以当你发现一个比你聪明的人时,就顺其自然吧。你的管理职责在很大程度上变成
了“听起来像是个好主意——去尝试吧”,或者“听起来不错,但是XXX呢?”“。第二个版
本尤其是一个很好的方法,要么学习一些关于“XXX”的新东西,要么通过指出一些聪明
人没有想到的东西来显得更具管理性。无论哪种情况,你都会赢。
要注意的一件事是认识到一个领域的伟大不一定会转化为其他领域。所以你可能会向
特定的方向刺激人们,但让我们面对现实吧,他们可能擅长他们所做的事情,而且对
其他事情都很差劲。好消息是,人们往往会自然而然地重拾他们擅长的东西,所以当
你向某个方向刺激他们时,你并不是在做不可逆转的事情,只是不要用力推。
4)责备
-------
事情会出问题的,人们希望去责备人。贴标签,你就是受责备的人。
事实上,接受责备并不难,尤其是当人们意识到这不 **全是** 你的过错时。这让我
们找到了承担责任的最佳方式:为别人承担这件事。你会感觉很好,他们会感觉很好,
没有受到指责. 那谁,失去了他们的全部36GB色情收藏的人,因为你的无能将勉强承
认,你至少没有试图逃避责任。
然后让真正搞砸了的开发人员(如果你能找到他们)私下知道他们搞砸了。不仅是为
了将来可以避免,而且为了让他们知道他们欠你一个人情。而且,也许更重要的是,
他们也可能是能够解决问题的人。因为,让我们面对现实吧,肯定不是你。
承担责任也是你首先成为管理者的原因。这是让人们信任你,让你获得潜在的荣耀的
一部分,因为你就是那个会说“我搞砸了”的人。如果你已经遵循了以前的规则,你现
在已经很擅长说了。
5)应避免的事情
---------------
有一件事人们甚至比被称为“笨蛋”更讨厌,那就是在一个神圣的声音中被称为“笨蛋”。
第一个你可以道歉,第二个你不会真正得到机会。即使你做得很好,他们也可能不再
倾听。
我们都认为自己比别人强,这意味着当别人装腔作势时,这会让我们很恼火。你也许
在道德和智力上比你周围的每个人都优越,但不要试图太明显,除非你真的打算激怒
某人 [#cnf3]_
同样,不要对事情太客气或太微妙。礼貌很容易落得落花流水,把问题隐藏起来,
正如他们所说,“在互联网上,没人能听到你的含蓄。”用一个钝器把这一点锤进去,
因为你不能真的依靠别人来获得你的观点。
一些幽默可以帮助缓和直率和道德化。过度到荒谬的地步,可以灌输一个观点,而不
会让接受者感到痛苦,他们只是认为你是愚蠢的。因此,它可以帮助我们摆脱对批评
的个人心理障碍。
.. [#cnf3] 提示:与你的工作没有直接关系的网络新闻组是消除你对他人不满的好
方法。偶尔写些侮辱性的帖子,打个喷嚏,让你的情绪得到净化。别把牢骚带回家
6)为什么是我?
---------------
既然你的主要责任似乎是为别人的错误承担责任,并且让别人痛苦地明白你是不称职
的,那么显而易见的问题之一就变成了为什么首先要这样做。
首先,虽然你可能会或可能不会听到十几岁女孩(或男孩,让我们不要在这里评判或
性别歧视)敲你的更衣室门,你会得到一个巨大的个人成就感为“负责”。别介意你真
的在领导别人,你要跟上别人,尽可能快地追赶他们。每个人都会认为你是负责人。
如果你可以做到这个, 这是个伟大的工作!
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/programming-language.rst <programming_language>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_programming_language:
程序设计语言
============
内核是用C语言 [c-language]_ 编写的。更准确地说,内核通常是用 ``gcc`` [gcc]_
在 ``-std=gnu89`` [gcc-c-dialect-options]_ 下编译的:ISO C90的 GNU 方言(
包括一些C99特性)
这种方言包含对语言 [gnu-extensions]_ 的许多扩展,当然,它们许多都在内核中使用。
对于一些体系结构,有一些使用 ``clang`` [clang]_ 和 ``icc`` [icc]_ 编译内核
的支持,尽管在编写此文档时还没有完成,仍需要第三方补丁。
属性
----
在整个内核中使用的一个常见扩展是属性(attributes) [gcc-attribute-syntax]_
属性允许将实现定义的语义引入语言实体(如变量、函数或类型),而无需对语言进行
重大的语法更改(例如添加新关键字) [n2049]_
在某些情况下,属性是可选的(即不支持这些属性的编译器仍然应该生成正确的代码,
即使其速度较慢或执行的编译时检查/诊断次数不够)
内核定义了伪关键字(例如, ``pure`` ),而不是直接使用GNU属性语法(例如,
``__attribute__((__pure__))`` ),以检测可以使用哪些关键字和/或缩短代码, 具体
请参阅 ``include/linux/compiler_attributes.h``
.. [c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
.. [gcc] https://gcc.gnu.org
.. [clang] https://clang.llvm.org
.. [icc] https://software.intel.com/en-us/c-compilers
.. [gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
.. [gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
.. [gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
.. [n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
Chinese translated version of Documentation/process/stable-api-nonsense.rst
.. _cn_stable_api_nonsense:
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.
.. include:: ../disclaimer-zh_CN.rst
Maintainer: Greg Kroah-Hartman <greg@kroah.com>
Chinese maintainer: TripleX Chung <zhongyu@18mail.cn>
---------------------------------------------------------------------
Documentation/process/stable-api-nonsense.rst 的中文翻译
:Original: :ref:`Documentation/process/stable-api-nonsense.rst
<stable_api_nonsense>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
译者::
英文版维护者: Greg Kroah-Hartman <greg@kroah.com>
中文版维护者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版翻译者: 钟宇 TripleX Chung <zhongyu@18mail.cn>
中文版校译者: 李阳 Li Yang <leoli@freescale.com>
以下为正文
---------------------------------------------------------------------
中文版维护者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
中文版翻译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
Linux 内核驱动接口
==================
写作本文档的目的,是为了解释为什么Linux既没有二进制内核接口,也没有稳定
的内核接口。这里所说的内核接口,是指内核里的接口,而不是内核和用户空间
......@@ -59,18 +51,22 @@ Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选
--------------
假如我们有一个稳定的内核源代码接口,那么自然而然的,我们就拥有了稳定的
二进制接口,是这样的吗?错。让我们看看关于Linux内核的几点事实:
- 取决于所用的C编译器的版本,不同的内核数据结构里的结构体的对齐方
式会有差别,代码中不同函数的表现形式也不一样(函数是不是被inline编译取
决于编译器行为)。不同的函数的表现形式并不重要,但是数据结构内部的对齐
方式很关键。
式会有差别,代码中不同函数的表现形式也不一样(函数是不是被inline
编译取决于编译器行为)。不同的函数的表现形式并不重要,但是数据
结构内部的对齐方式很关键。
- 取决于内核的配置选项,不同的选项会让内核的很多东西发生改变:
- 同一个结构体可能包含不同的成员变量
- 有的函数可能根本不会被实现(比如编译的时候没有选择SMP支持
一些锁函数就会被定义成空函数)。
一些锁函数就会被定义成空函数)。
- 内核使用的内存会以不同的方式对齐,这取决于不同的内核配置选
项。
项。
- Linux可以在很多的不同体系结构的处理器上运行。在某个体系结构上编
译好的二进制驱动程序,不可能在另外一个体系结构上正确的运行。
译好的二进制驱动程序,不可能在另外一个体系结构上正确的运行。
对于一个特定的内核,满足这些条件并不难,使用同一个C编译器和同样的内核配
置选项来编译驱动程序模块就可以了。这对于给一个特定Linux发布的特定版本提
......@@ -90,7 +86,7 @@ Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选
如果有人不将他的内核驱动程序,放入公版内核的源代码树,而又想让驱动程序
一直保持在最新的内核中可用,那么这个话题将会变得没完没了。
内核开发是持续而且快节奏的,从来都不会慢下来。内核开发人员在当前接口中
内核开发是持续而且快节奏的,从来都不会慢下来。内核开发人员在当前接口中
找到bug,或者找到更好的实现方式。一旦发现这些,他们就很快会去修改当前的
接口。修改接口意味着,函数名可能会改变,结构体可能被扩充或者删减,函数
的参数也可能发生改变。一旦接口被修改,内核中使用这些接口的地方需要同时
......@@ -98,21 +94,22 @@ Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选
举一个例子,内核的USB驱动程序接口在USB子系统的整个生命周期中,至少经历
了三次重写。这些重写解决以下问题:
- 把数据流从同步模式改成非同步模式,这个改动减少了一些驱动程序的
复杂度,提高了所有USB驱动程序的吞吐率,这样几乎所有的USB设备都能以最大
速率工作了。
复杂度,提高了所有USB驱动程序的吞吐率,这样几乎所有的USB设备都
能以最大速率工作了。
- 修改了USB核心代码中为USB驱动分配数据包内存的方式,所有的驱动都
需要提供更多的参数给USB核心,以修正了很多已经被记录在案的死锁。
需要提供更多的参数给USB核心,以修正了很多已经被记录在案的死锁。
这和一些封闭源代码的操作系统形成鲜明的对比,在那些操作系统上,不得不额
外的维护旧的USB接口。这导致了一个可能性,新的开发者依然会不小心使用旧的
接口,以不恰当的方式编写代码,进而影响到操作系统的稳定性。
在上面的例子中,所有的开发者都同意这些重要的改动,在这样的情况下修改代
在上面的例子中,所有的开发者都同意这些重要的改动,在这样的情况下修改代
价很低。如果Linux保持一个稳定的内核源代码接口,那么就得创建一个新的接口
;旧的,有问题的接口必须一直维护,给Linux USB开发者带来额外的工作。既然
所有的Linux USB驱动的作者都是利用自己的时间工作,那么要求他们去做毫无意
义的免费额外工作,是不可能的。
安全问题对Linux来说十分重要。一个安全问题被发现,就会在短时间内得到修
安全问题对Linux来说十分重要。一个安全问题被发现,就会在短时间内得到修
正。在很多情况下,这将导致Linux内核中的一些接口被重写,以从根本上避免安
全问题。一旦接口被重写,所有使用这些接口的驱动程序,必须同时得到修正,
以确定安全问题已经得到修复并且不可能在未来还有同样的安全问题。如果内核
......@@ -124,7 +121,7 @@ Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选
要做什么
-------
--------
如果你写了一个Linux内核驱动,但是它还不在Linux源代码树里,作为一个开发
者,你应该怎么做?为每个发布的每个版本提供一个二进制驱动,那简直是一个
......@@ -137,20 +134,21 @@ Linux能成为强壮,稳定,成熟的操作系统,这也是你最开始选
做什么事情。
把驱动放到内核源代码树里会有很多的好处:
- 驱动的质量会提升,而维护成本(对原始作者来说)会下降。
- 其他人会给驱动添加新特性。
- 其他人会找到驱动中的bug并修复。
- 其他人会在驱动中找到性能优化的机会。
- 当外部的接口的改变需要修改驱动程序的时候,其他人会修改驱动程序
- 不需要联系任何发行商,这个驱动会自动的随着所有的Linux发布一起发
布。
布。
和别的操作系统相比,Linux为更多不同的设备提供现成的驱动,而且能在更多不
同体系结构的处理器上支持这些设备。这个经过考验的开发模式,必然是错不了
的 :)
-------------
感谢
----
感谢 Randy Dunlap, Andrew Morton, David Brownell, Hanna Linder,
Robert Love, and Nishanth Aravamudan 对于本文档早期版本的评审和建议。
......
Chinese translated version of Documentation/process/stable-kernel-rules.rst
.. _cn_stable_kernel_rules:
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.
.. include:: ../disclaimer-zh_CN.rst
Chinese maintainer: TripleX Chung <triplex@zh-kernel.org>
---------------------------------------------------------------------
Documentation/process/stable-kernel-rules.rst 的中文翻译
:Original: :ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者
译存在问题,请联系中文版维护者::
中文版维护者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
中文版翻译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
中文版校译者:
- 李阳 Li Yang <leoyang.li@nxp.com>
- Kangkai Yin <e12051@motorola.com>
中文版维护者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版翻译者: 钟宇 TripleX Chung <triplex@zh-kernel.org>
中文版校译者: 李阳 Li Yang <leo@zh-kernel.org>
Kangkai Yin <e12051@motorola.com>
以下为正文
---------------------------------------------------------------------
所有你想知道的事情 - 关于linux稳定版发布
========================================
关于Linux 2.6稳定版发布,所有你想知道的事情。
关于哪些类型的补丁可以被接收进入稳定版代码树,哪些不可以的规则:
----------------------------------------------------------------
- 必须是显而易见的正确,并且经过测试的。
- 连同上下文,不能大于100行。
......@@ -38,9 +33,10 @@ Documentation/process/stable-kernel-rules.rst 的中文翻译
- 没有“理论上的竞争条件”,除非能给出竞争条件如何被利用的解释。
- 不能存在任何的“琐碎的”修正(拼写修正,去掉多余空格之类的)。
- 必须被相关子系统的维护者接受。
- 必须遵循Documentation/process/submitting-patches.rst里的规则。
- 必须遵循Documentation/translations/zh_CN/process/submitting-patches.rst里的规则。
向稳定版代码树提交补丁的过程:
------------------------------
- 在确认了补丁符合以上的规则后,将补丁发送到stable@vger.kernel.org。
- 如果补丁被接受到队列里,发送者会收到一个ACK回复,如果没有被接受,收
......@@ -49,6 +45,7 @@ Documentation/process/stable-kernel-rules.rst 的中文翻译
- 安全方面的补丁不要发到这个列表,应该发送到security@kernel.org。
审查周期:
----------
- 当稳定版的维护者决定开始一个审查周期,补丁将被发送到审查委员会,以
及被补丁影响的领域的维护者(除非提交者就是该领域的维护者)并且抄送
......@@ -63,4 +60,5 @@ Documentation/process/stable-kernel-rules.rst 的中文翻译
通常的审查周期。请联系内核安全小组以获得关于这个过程的更多细节。
审查委员会:
------------
- 由一些自愿承担这项任务的内核开发者,和几个非志愿的组成。
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
.. _cn_submitchecklist:
Linux内核补丁提交清单
~~~~~~~~~~~~~~~~~~~~~
如果开发人员希望看到他们的内核补丁提交更快地被接受,那么他们应该做一些基本
的事情。
这些都是在
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
和其他有关提交Linux内核补丁的文档中提供的。
1) 如果使用工具,则包括定义/声明该工具的文件。不要依赖于其他头文件拉入您使用
的头文件。
2) 干净的编译:
a) 使用适用或修改的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有GCC
警告/错误,没有链接器警告/错误。
b) 通过allnoconfig、allmodconfig
c) 使用 ``O=builddir`` 时可以成功编译
3) 通过使用本地交叉编译工具或其他一些构建场在多个CPU体系结构上构建。
4) PPC64是一种很好的交叉编译检查体系结构,因为它倾向于对64位的数使用无符号
长整型。
5) 如下所述 :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`.
检查您的补丁是否为常规样式。在提交( ``scripts/check patch.pl`` )之前,
使用补丁样式检查器检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
违规行为。
6) 任何新的或修改过的 ``CONFIG`` 选项都不会弄脏配置菜单,并默认为关闭,除非
它们符合 ``Documentation/kbuild/kconfig-language.txt`` 中记录的异常条件,
菜单属性:默认值.
7) 所有新的 ``kconfig`` 选项都有帮助文本。
8) 已仔细审查了相关的 ``Kconfig`` 组合。这很难用测试来纠正——脑力在这里是有
回报的。
9) 用 sparse 检查干净。
10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何
问题。
.. note::
``checkstack`` 并没有明确指出问题,但是任何一个在堆栈上使用超过512
字节的函数都可以进行更改。
11) 包括 :ref:`kernel-doc <kernel_doc>` 内核文档以记录全局内核API。(静态函数
不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
:ref:`kernel-doc <kernel_doc>` 并修复任何问题。
12) 通过以下选项同时启用的测试 ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
``CONFIG_PROVE_RCU`` and ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``
13) 已经过构建和运行时测试,包括有或没有 ``CONFIG_SMP``, ``CONFIG_PREEMPT``.
14) 如果补丁程序影响IO/磁盘等:使用或不使用 ``CONFIG_LBDAF`` 进行测试。
15) 所有代码路径都已在启用所有lockdep功能的情况下运行。
16) 所有新的/proc条目都记录在 ``Documentation/``
17) 所有新的内核引导参数都记录在
Documentation/admin-guide/kernel-parameters.rst 中。
18) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``
19) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息,
请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送
linux-api@vger.kernel.org。
20) 检查是否全部通过 ``make headers_check`` 。
21) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/``
如果新代码是实质性的,那么添加子系统特定的故障注入可能是合适的。
22) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这
将产生大量噪声,但对于查找诸如“警告:有符号和无符号之间的比较”之类的错误
很有用。
23) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以
及VM、VFS和其他子系统中的各种更改一起工作。
24) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注
释来解释它们正在执行的操作及其原因的逻辑。
25) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/ioctl/ioctl-number.txt``
26) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况
下测试以下多个构建[并非所有这些都同时存在,只是它们的各种/随机组合]:
``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
``CONFIG_NET``, ``CONFIG_INET=n`` (但是后者伴随 ``CONFIG_NET=y``).
Chinese translated version of Documentation/process/submitting-drivers.rst
.. _cn_submittingdrivers:
If you have any comment or update to the content, please contact the
original document maintainer directly. However, if you have a problem
communicating in English you can also ask the Chinese maintainer for
help. Contact the Chinese maintainer if this translation is outdated
or if there is a problem with the translation.
.. include:: ../disclaimer-zh_CN.rst
Chinese maintainer: Li Yang <leo@zh-kernel.org>
---------------------------------------------------------------------
Documentation/process/submitting-drivers.rst 的中文翻译
:Original: :ref:`Documentation/process/submitting-drivers.rst
<submittingdrivers>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者
译存在问题,请联系中文版维护者::
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
张巍 Zhang Wei <Wei.Zhang@freescale.com>
以下为正文
---------------------------------------------------------------------
中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com>
中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com>
中文版校译者: 陈琦 Maggie Chen <chenqi@beyondsoft.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
张巍 Zhang Wei <wezhang@outlook.com>
如何向 Linux 内核提交驱动程序
-----------------------------
=============================
这篇文档将会解释如何向不同的内核源码树提交设备驱动程序。请注意,如果你感
兴趣的是显卡驱动程序,你也许应该访问 XFree86 项目(http://www.xfree86.org/)
和/或 X.org 项目 (http://x.org)。
另请参阅 Documentation/process/submitting-patches.rst 文档。
另请参阅 Documentation/Documentation/translations/zh_CN/process/submitting-patches.rst 文档。
分配设备号
......@@ -145,9 +137,13 @@ Linux 设备驱动程序,第三版(探讨 2.6.10 版内核):
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):
......
.. _cn_submittingpatches:
.. include:: ../disclaimer-zh_CN.rst
:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
译者::
中文版维护者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
中文版翻译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
王聪 Wang Cong <xiyou.wangcong@gmail.com>
如何让你的改动进入内核
======================
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
的改动被接受的机会.
以下文档含有大量简洁的建议, 具体请见:
:ref:`Documentation/process <development_process_main>`
同样,:ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`
给出在提交代码前需要检查的项目的列表。如果你在提交一个驱动程序,那么
同时阅读一下:
:ref:`Documentation/process/submitting-drivers.rst <submittingdrivers>`
其中许多步骤描述了Git版本控制系统的默认行为;如果您使用Git来准备补丁,
您将发现它为您完成的大部分机械工作,尽管您仍然需要准备和记录一组合理的
补丁。一般来说,使用git将使您作为内核开发人员的生活更轻松。
0) 获取当前源码树
-----------------
如果您没有一个可以使用当前内核源代码的存储库,请使用git获取一个。您将要
从主线存储库开始,它可以通过以下方式获取::
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
但是,请注意,您可能不希望直接针对主线树进行开发。大多数子系统维护人员运
行自己的树,并希望看到针对这些树准备的补丁。请参见MAINTAINERS文件中子系
统的 **T:** 项以查找该树,或者简单地询问维护者该树是否未在其中列出。
仍然可以通过tarballs下载内核版本(如下一节所述),但这是进行内核开发的
一种困难的方式。
1) "diff -up"
-------------
使用 "diff -up" 或者 "diff -uprN" 来创建补丁。
所有内核的改动,都是以补丁的形式呈现的,补丁由 diff(1) 生成。创建补丁的
时候,要确认它是以 "unified diff" 格式创建的,这种格式由 diff(1) 的 '-u'
参数生成。而且,请使用 '-p' 参数,那样会显示每个改动所在的C函数,使得
产生的补丁容易读得多。补丁应该基于内核源代码树的根目录,而不是里边的任
何子目录。
为一个单独的文件创建补丁,一般来说这样做就够了::
SRCTREE=linux
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
tar xvfz linux-3.19.tar.gz
mv linux-3.19 linux-3.19-vanilla
diff -uprN -X linux-3.19-vanilla/Documentation/dontdiff \
linux-3.19-vanilla $MYSRC > /tmp/patch
"dontdiff" 是内核在编译的时候产生的文件的列表,列表中的文件在 diff(1)
产生的补丁里会被跳过。
确定你的补丁里没有包含任何不属于这次补丁提交的额外文件。记得在用diff(1)
生成补丁之后,审阅一次补丁,以确保准确。
如果你的改动很散乱,你应该研究一下如何将补丁分割成独立的部分,将改动分
割成一系列合乎逻辑的步骤。这样更容易让其他内核开发者审核,如果你想你的
补丁被接受,这是很重要的。请参阅:
:ref:`cn_split_changes`
如果你用 ``git`` , ``git rebase -i`` 可以帮助你这一点。如果你不用 ``git``,
``quilt`` <http://savannah.nongnu.org/projects/quilt> 另外一个流行的选择。
.. _cn_describe_changes:
2) 描述你的改动
---------------
描述你的问题。无论您的补丁是一行错误修复还是5000行新功能,都必须有一个潜在
的问题激励您完成这项工作。让审稿人相信有一个问题值得解决,让他们读完第一段
是有意义的。
描述用户可见的影响。直接崩溃和锁定是相当有说服力的,但并不是所有的错误都那么
明目张胆。即使在代码审查期间发现了这个问题,也要描述一下您认为它可能对用户产
生的影响。请记住,大多数Linux安装运行的内核来自二级稳定树或特定于供应商/产品
的树,只从上游精选特定的补丁,因此请包含任何可以帮助您将更改定位到下游的内容:
触发的场景、DMESG的摘录、崩溃描述、性能回归、延迟尖峰、锁定等。
量化优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
改进,请包括支持它们的数字。但也要描述不明显的成本。优化通常不是免费的,而是
在CPU、内存和可读性之间进行权衡;或者,探索性的工作,在不同的工作负载之间进
行权衡。请描述优化的预期缺点,以便审阅者可以权衡成本和收益。
一旦问题建立起来,就要详细地描述一下您实际在做什么。对于审阅者来说,用简单的
英语描述代码的变化是很重要的,以验证代码的行为是否符合您的意愿。
如果您将补丁描述写在一个表单中,这个表单可以很容易地作为“提交日志”放入Linux
的源代码管理系统git中,那么维护人员将非常感谢您。见 :ref:`cn_explicit_in_reply_to`.
每个补丁只解决一个问题。如果你的描述开始变长,这就表明你可能需要拆分你的补丁。
请见 :ref:`cn_split_changes`
提交或重新提交修补程序或修补程序系列时,请包括完整的修补程序说明和理由。不要
只说这是补丁(系列)的第几版。不要期望子系统维护人员引用更早的补丁版本或引用
URL来查找补丁描述并将其放入补丁中。也就是说,补丁(系列)及其描述应该是独立的。
这对维护人员和审查人员都有好处。一些评审者可能甚至没有收到补丁的早期版本。
描述你在命令语气中的变化,例如“make xyzzy do frotz”而不是“[这个补丁]make
xyzzy do frotz”或“[我]changed xyzzy to do frotz”,就好像你在命令代码库改变
它的行为一样。
如果修补程序修复了一个记录的bug条目,请按编号和URL引用该bug条目。如果补丁来
自邮件列表讨论,请给出邮件列表存档的URL;使用带有 ``Message-ID`` 的
https://lkml.kernel.org/ 重定向,以确保链接不会过时。
但是,在没有外部资源的情况下,尽量让你的解释可理解。除了提供邮件列表存档或
bug的URL之外,还要总结需要提交补丁的相关讨论要点。
如果您想要引用一个特定的提交,不要只引用提交的 SHA-1 ID。还请包括提交的一行
摘要,以便于审阅者了解它是关于什么的。例如::
Commit e21d2170f36602ae2708 ("video: remove unnecessary
platform_set_drvdata()") removed the unnecessary
platform_set_drvdata(), but left the variable "dev" unused,
delete it.
您还应该确保至少使用前12位 SHA-1 ID. 内核存储库包含*许多*对象,使与较短的ID
发生冲突的可能性很大。记住,即使现在不会与您的六个字符ID发生冲突,这种情况
可能五年后改变。
如果修补程序修复了特定提交中的错误,例如,使用 ``git bisct`` ,请使用带有前
12个字符SHA-1 ID 的"Fixes:"标记和单行摘要。为了简化不要将标记拆分为多个,
行、标记不受分析脚本“75列换行”规则的限制。例如::
Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
下列 ``git config`` 设置可以添加让 ``git log``, ``git show`` 漂亮的显示格式::
[core]
abbrev = 12
[pretty]
fixes = Fixes: %h (\"%s\")
.. _cn_split_changes:
3) 拆分你的改动
---------------
将每个逻辑更改分隔成一个单独的补丁。
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动拆分到两个或
者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
应这些新的API,那么把这些修改分成两个补丁。
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
丁描述里指出“这个补丁依赖某补丁”就好了。
在将您的更改划分为一系列补丁时,要特别注意确保内核在系列中的每个补丁之后
都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何时
候分割你的补丁系列;如果你在中间引入错误,他们不会感谢你。
如果你不能将补丁浓缩成更少的文件,那么每次大约发送出15个,然后等待审查
和集成。
4) 检查你的更改风格
-------------------
检查您的补丁是否存在基本样式冲突,详细信息可在
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
中找到。如果不这样做,只会浪费审稿人的时间,并且会导致你的补丁被拒绝,甚至
可能没有被阅读。
一个重要的例外是在将代码从一个文件移动到另一个文件时——在这种情况下,您不应
该在移动代码的同一个补丁中修改移动的代码。这清楚地描述了移动代码和您的更改
的行为。这大大有助于审查实际差异,并允许工具更好地跟踪代码本身的历史。
在提交之前,使用补丁样式检查程序检查补丁(scripts/check patch.pl)。不过,
请注意,样式检查程序应该被视为一个指南,而不是作为人类判断的替代品。如果您
的代码看起来更好,但有违规行为,那么最好不要使用它。
检查者报告三个级别:
- ERROR:很可能出错的事情
- WARNING:需要仔细审查的事项
- CHECK:需要思考的事情
您应该能够判断您的补丁中存在的所有违规行为。
5) 选择补丁收件人
-----------------
您应该总是在任何补丁上复制相应的子系统维护人员,以获得他们维护的代码;查看
维护人员文件和源代码修订历史记录,以了解这些维护人员是谁。脚本
scripts/get_Maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
的维护人员,那么Andrew Morton(akpm@linux-foundation.org)将充当最后的维护
人员。
您通常还应该选择至少一个邮件列表来接收补丁集的。linux-kernel@vger.kernel.org
作为最后一个解决办法的列表,但是这个列表上的体积已经引起了许多开发人员的拒绝。
在MAINTAINERS文件中查找子系统特定的列表;您的补丁可能会在那里得到更多的关注。
不过,请不要发送垃圾邮件到无关的列表。
许多与内核相关的列表托管在vger.kernel.org上;您可以在
http://vger.kernel.org/vger-lists.html 上找到它们的列表。不过,也有与内核相关
的列表托管在其他地方。
不要一次发送超过15个补丁到vger邮件列表!!!!
Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
的说,最好别给他发 e-mail。
如果您有修复可利用安全漏洞的补丁,请将该补丁发送到 security@kernel.org。对于
严重的bug,可以考虑短期暂停以允许分销商向用户发布补丁;在这种情况下,显然不应
将补丁发送到任何公共列表。
修复已发布内核中严重错误的补丁程序应该指向稳定版维护人员,方法是放这样的一行::
Cc: stable@vger.kernel.org
进入补丁的签准区(注意,不是电子邮件收件人)。除了这个文件之外,您还应该阅读
:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
但是,请注意,一些子系统维护人员希望得出他们自己的结论,即哪些补丁应该被放到
稳定的树上。尤其是网络维护人员,不希望看到单个开发人员在补丁中添加像上面这样
的行。
如果更改影响到用户和内核接口,请向手册页维护人员(如维护人员文件中所列)发送
手册页补丁,或至少发送更改通知,以便一些信息进入手册页。还应将用户空间API
更改复制到 linux-api@vger.kernel.org。
对于小的补丁,你也许会CC到搜集琐碎补丁的邮件列表(Trivial Patch Monkey)
trivial@kernel.org,那里专门收集琐碎的补丁。下面这样的补丁会被看作“琐碎的”
补丁:
- 文档的拼写修正。
- 修正会影响到 grep(1) 的拼写。
- 警告信息修正(频繁的打印无用的警告是不好的。)
- 编译错误修正(代码逻辑的确是对的,只是编译有问题。)
- 运行时修正(只要真的修正了错误。)
- 移除使用了被废弃的函数/宏的代码(例如 check_region。)
- 联系方式和文档修正。
- 用可移植的代码替换不可移植的代码(即使在体系结构相关的代码中,既然有
- 人拷贝,只要它是琐碎的)
- 任何文件的作者/维护者对该文件的改动(例如 patch monkey 在重传模式下)
(译注,关于“琐碎补丁”的一些说明:因为原文的这一部分写得比较简单,所以不得不
违例写一下译注。"trivial"这个英文单词的本意是“琐碎的,不重要的。”但是在这里
有稍微有一些变化,例如对一些明显的NULL指针的修正,属于运行时修正,会被归类
到琐碎补丁里。虽然NULL指针的修正很重要,但是这样的修正往往很小而且很容易得到
检验,所以也被归入琐碎补丁。琐碎补丁更精确的归类应该是
“simple, localized & easy to verify”,也就是说简单的,局部的和易于检验的。
trivial@kernel.org邮件列表的目的是针对这样的补丁,为提交者提供一个中心,来
降低提交的门槛。)
6) 没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本
-----------------------------------------------------------
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
代码的任何位置添加评论。
因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
.. warning::
如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的补丁
不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
代码中加评论。另外,MIME 编码的附件会让 Linus 多花一点时间来处理,这就
降低了你的改动被接受的可能性。
例外:如果你的邮递员弄坏了补丁,那么有人可能会要求你使用mime重新发送补丁
请参阅 :ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>`
以获取有关配置电子邮件客户端以使其不受影响地发送修补程序的提示。
7) e-mail 的大小
----------------
大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
的情况下,超过了300kB,那么你最好将补丁放在一个能通过 internet 访问的服
务器上,然后用指向你的补丁的 URL 替代。但是请注意,如果您的补丁超过了
300kb,那么它几乎肯定需要被破坏。
8)回复评审意见
---------------
你的补丁几乎肯定会得到评审者对补丁改进方法的评论。您必须对这些评论作出
回应;让补丁被忽略的一个好办法就是忽略审阅者的意见。不会导致代码更改的
意见或问题几乎肯定会带来注释或变更日志的改变,以便下一个评审者更好地了解
正在发生的事情。
一定要告诉审稿人你在做什么改变,并感谢他们的时间。代码审查是一个累人且
耗时的过程,审查人员有时会变得暴躁。即使在这种情况下,也要礼貌地回应并
解决他们指出的问题。
9)不要泄气或不耐烦
-------------------
提交更改后,请耐心等待。审阅者是忙碌的人,可能无法立即访问您的修补程序。
曾几何时,补丁曾在没有评论的情况下消失在空白中,但开发过程比现在更加顺利。
您应该在一周左右的时间内收到评论;如果没有收到评论,请确保您已将补丁发送
到正确的位置。在重新提交或联系审阅者之前至少等待一周-在诸如合并窗口之类的
繁忙时间可能更长。
10)主题中包含 PATCH
--------------------
由于到linus和linux内核的电子邮件流量很高,通常会在主题行前面加上[PATCH]
前缀. 这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。
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 的一些特殊细节。
如果您是子系统或分支维护人员,有时需要稍微修改收到的补丁,以便合并它们,
因为树和提交者中的代码不完全相同。如果你严格遵守规则(c),你应该要求提交者
重新发布,但这完全是在浪费时间和精力。规则(b)允许您调整代码,但是更改一个
提交者的代码并让他认可您的错误是非常不礼貌的。要解决此问题,建议在最后一个
由签名行和您的行之间添加一行,指示更改的性质。虽然这并不是强制性的,但似乎
在描述前加上您的邮件和/或姓名(全部用方括号括起来),这足以让人注意到您对最
后一分钟的更改负有责任。例如::
Signed-off-by: Random J Developer <random@developer.example.org>
[lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
如果您维护一个稳定的分支机构,同时希望对作者进行致谢、跟踪更改、合并修复并
保护提交者不受投诉,那么这种做法尤其有用。请注意,在任何情况下都不能更改作者
的ID(From 头),因为它是出现在更改日志中的标识。
对回合(back-porters)的特别说明:在提交消息的顶部(主题行之后)插入一个补丁
的起源指示似乎是一种常见且有用的实践,以便于跟踪。例如,下面是我们在3.x稳定
版本中看到的内容::
Date: Tue Oct 7 07:26:38 2014 -0400
libata: Un-break ATA blacklist
commit 1c40279960bcd7d52dbdf1d466b20d24b99176c8 upstream.
还有, 这里是一个旧版内核中的一个回合补丁::
Date: Tue May 13 22:12:27 2008 +0200
wireless, airo: waitbusy() won't delay
[backport of 2.6 commit b7acbdfbd1f277c1eb23f344f899cfa4cd0bf36a]
12)何时使用Acked-by:,CC:,和Co-Developed by:
----------------------------------------------
Singed-off-by: 标记表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。
如果一个人没有直接参与补丁的准备或处理,但希望表示并记录他们对补丁的批准,
那么他们可以要求在补丁的变更日志中添加一个 Acked-by:
Acked-by:通常由受影响代码的维护者使用,当该维护者既没有贡献也没有转发补丁时。
Acked-by: 不像签字人那样正式。这是一个记录,确认人至少审查了补丁,并表示接受。
因此,补丁合并有时会手动将Acker的“Yep,looks good to me”转换为 Acked-By:(但
请注意,通常最好要求一个明确的Ack)。
Acked-by:不一定表示对整个补丁的确认。例如,如果一个补丁影响多个子系统,并且
有一个:来自一个子系统维护者,那么这通常表示只确认影响维护者代码的部分。这里
应该仔细判断。如有疑问,应参考邮件列表档案中的原始讨论。
如果某人有机会对补丁进行评论,但没有提供此类评论,您可以选择在补丁中添加 ``Cc:``
这是唯一一个标签,它可以在没有被它命名的人显式操作的情况下添加,但它应该表明
这个人是在补丁上抄送的。讨论中包含了潜在利益相关方。
Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上工
作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为
Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟在相关合作作者的
签名之后。标准的签核程序要求:标记的签核顺序应尽可能反映补丁的时间历史,而不
管作者是通过 From :还是由 Co-developed-by: 共同开发的。值得注意的是,最后一
个签字人:必须始终是提交补丁的开发人员。
注意,当作者也是电子邮件标题“发件人:”行中列出的人时,“From: ” 标记是可选的。
作者提交的补丁程序示例::
<changelog>
Co-developed-by: First Co-Author <first@coauthor.example.org>
Signed-off-by: First Co-Author <first@coauthor.example.org>
Co-developed-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: Second Co-Author <second@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
合作开发者提交的补丁示例::
From: From Author <from@author.example.org>
<changelog>
Co-developed-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: Random Co-Author <random@coauthor.example.org>
Signed-off-by: From Author <from@author.example.org>
Co-developed-by: Submitting Co-Author <sub@coauthor.example.org>
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
13)使用报告人:、测试人:、审核人:、建议人:、修复人:
--------------------------------------------------------
Reported-by: 给那些发现错误并报告错误的人致谢,它希望激励他们在将来再次帮助
我们。请注意,如果bug是以私有方式报告的,那么在使用Reported-by标记之前,请
先请求权限。
Tested-by: 标记表示补丁已由指定的人(在某些环境中)成功测试。这个标签通知
维护人员已经执行了一些测试,为将来的补丁提供了一种定位测试人员的方法,并确
保测试人员的信誉。
Reviewed-by:相反,根据审查人的声明,表明该补丁已被审查并被认为是可接受的:
审查人的监督声明
^^^^^^^^^^^^^^^^
通过提供我的 Reviewed-by,我声明:
(a) 我已经对这个补丁进行了一次技术审查,以评估它是否适合被包含到
主线内核中。
(b) 与补丁相关的任何问题、顾虑或问题都已反馈给提交者。我对提交者对
我的评论的回应感到满意。
(c) 虽然这一提交可能会改进一些东西,但我相信,此时,(1)对内核
进行了有价值的修改,(2)没有包含争论中涉及的已知问题。
(d) 虽然我已经审查了补丁并认为它是健全的,但我不会(除非另有明确
说明)作出任何保证或保证它将在任何给定情况下实现其规定的目的
或正常运行。
Reviewed-by 是一种观点声明,即补丁是对内核的适当修改,没有任何遗留的严重技术
问题。任何感兴趣的审阅者(完成工作的人)都可以为一个补丁提供一个 Review-by
标签。此标签用于向审阅者提供致谢,并通知维护者已在修补程序上完成的审阅程度。
Reviewed-by: 当由已知了解主题区域并执行彻底检查的审阅者提供时,通常会增加
补丁进入内核的可能性。
Suggested-by: 表示补丁的想法是由指定的人提出的,并确保将此想法归功于指定的
人。请注意,未经许可,不得添加此标签,特别是如果该想法未在公共论坛上发布。
这就是说,如果我们勤快地致谢我们的创意者,他们很有希望在未来得到鼓舞,再次
帮助我们。
Fixes: 指示补丁在以前的提交中修复了一个问题。它可以很容易地确定错误的来源,
这有助于检查错误修复。这个标记还帮助稳定内核团队确定应该接收修复的稳定内核
版本。这是指示补丁修复的错误的首选方法。请参阅 :ref:`cn_describe_changes`
描述您的更改以了解更多详细信息。
.. _cn_the_canonical_patch_format:
12)标准补丁格式
----------------
本节描述如何格式化补丁本身。请注意,如果您的补丁存储在 ``Git`` 存储库中,则
可以使用 ``git format-patch`` 进行正确的补丁格式设置。但是,这些工具无法创建
必要的文本,因此请务必阅读下面的说明。
标准的补丁,标题行是::
Subject: [PATCH 001/123] 子系统:一句话概述
标准补丁的信体存在如下部分:
- 一个 "from" 行指出补丁作者。后跟空行(仅当发送修补程序的人不是作者时才需要)。
- 解释的正文,行以75列包装,这将被复制到永久变更日志来描述这个补丁。
- 一个空行
- 上面描述的“Signed-off-by” 行,也将出现在更改日志中。
- 只包含 ``---`` 的标记线。
- 任何其他不适合放在变更日志的注释。
- 实际补丁( ``diff`` 输出)。
标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
丁),不要对每个补丁都使用同样的“一句话概述”。
记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
章。当人们在两三个月后使用诸如 ``gitk`` 或 ``git log --oneline`` 之类
的工具查看数千个补丁时,也会很快看到它。
出于这些原因,概述必须不超过70-75个字符,并且必须描述补丁的更改以及为
什么需要补丁。既要简洁又要描述性很有挑战性,但写得好的概述应该这样做。
概述的前缀可以用方括号括起来:“Subject: [PATCH <tag>...] <概述>”。标记
不被视为概述的一部分,而是描述应该如何处理补丁。如果补丁的多个版本已发
送出来以响应评审(即“v1,v2,v3”)或“rfc”,以指示评审请求,那么通用标记
可能包括版本描述符。如果一个补丁系列中有四个补丁,那么各个补丁可以这样
编号:1/4、2/4、3/4、4/4。这可以确保开发人员了解补丁应用的顺序,并且他们
已经查看或应用了补丁系列中的所有补丁。
一些标题的例子::
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
Subject: [PATCHv2 001/207] x86: fix eflags tracking
"From" 行是信体里的最上面一行,具有如下格式:
From: Patch Author <author@example.com>
"From" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "From" 行,那
么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
这个补丁相关的讨论细节的有能力的读者来说,是有意义的。包括补丁程序定位
错误的(内核日志消息、OOPS消息等)症状,对于搜索提交日志以寻找适用补丁的人
尤其有用。如果一个补丁修复了一个编译失败,那么可能不需要包含所有编译失败;
只要足够让搜索补丁的人能够找到它就行了。与概述一样,既要简洁又要描述性。
"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
的。
对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat,用来显
示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
动日志里的,也应该放这里。
使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
在后面的参考资料中能看到适当的补丁格式的更多细节。
.. _cn_explicit_in_reply_to:
15) 明确回复邮件头(In-Reply-To)
-------------------------------
手动添加回复补丁的的标题头(In-Reply_To:) 是有帮助的(例如,使用 ``git send-email`` )
将补丁与以前的相关讨论关联起来,例如,将bug修复程序链接到电子邮件和bug报告。
但是,对于多补丁系列,最好避免在回复时使用链接到该系列的旧版本。这样,
补丁的多个版本就不会成为电子邮件客户端中无法管理的引用序列。如果链接有用,
可以使用 https://lkml.kernel.org/ 重定向器(例如,在封面电子邮件文本中)
链接到补丁系列的早期版本。
16) 发送git pull请求
--------------------
如果您有一系列补丁,那么让维护人员通过git pull操作将它们直接拉入子系统存储
库可能是最方便的。但是,请注意,从开发人员那里获取补丁比从邮件列表中获取补
丁需要更高的信任度。因此,许多子系统维护人员不愿意接受请求,特别是来自新的
未知开发人员的请求。如果有疑问,您可以在封面邮件中使用pull 请求作为补丁系列
正常发布的一个选项,让维护人员可以选择使用其中之一。
pull 请求的主题行中应该有[Git Pull]。请求本身应该在一行中包含存储库名称和
感兴趣的分支;它应该看起来像::
Please pull from
git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus
to get these changes:
pull 请求还应该包含一条整体消息,说明请求中将包含什么,一个补丁本身的 ``Git shortlog``
以及一个显示补丁系列整体效果的 ``diffstat`` 。当然,将所有这些信息收集在一起
的最简单方法是让 ``git`` 使用 ``git request-pull`` 命令为您完成这些工作。
一些维护人员(包括Linus)希望看到来自已签名提交的请求;这增加了他们对你的
请求信心。特别是,在没有签名标签的情况下,Linus 不会从像 Github 这样的公共
托管站点拉请求。
创建此类签名的第一步是生成一个 GNRPG 密钥,并由一个或多个核心内核开发人员对
其进行签名。这一步对新开发人员来说可能很困难,但没有办法绕过它。参加会议是
找到可以签署您的密钥的开发人员的好方法。
一旦您在Git 中准备了一个您希望有人拉的补丁系列,就用 ``git tag -s`` 创建一
个签名标记。这将创建一个新标记,标识该系列中的最后一次提交,并包含用您的私
钥创建的签名。您还可以将changelog样式的消息添加到标记中;这是一个描述拉请求
整体效果的理想位置。
如果维护人员将要从中提取的树不是您正在使用的存储库,请不要忘记将已签名的标记
显式推送到公共树。
生成拉请求时,请使用已签名的标记作为目标。这样的命令可以实现::
git request-pull master git://my.public.tree/linux.git my-signed-tag
参考文献
--------
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/linux/maintainer.html>
<http://www.kroah.com/log/linux/maintainer-02.html>
<http://www.kroah.com/log/linux/maintainer-03.html>
<http://www.kroah.com/log/linux/maintainer-04.html>
<http://www.kroah.com/log/linux/maintainer-05.html>
<http://www.kroah.com/log/linux/maintainer-06.html>
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:
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
Linus Torvalds's mail on the canonical patch format:
<http://lkml.org/lkml/2005/4/7/183>
Andi Kleen, "On submitting kernel patches"
Some strategies to get difficult or controversial changes in.
http://halobates.de/on-submitting-patches.pdf
Chinese translated version of Documentation/process/volatile-considered-harmful.rst
.. _cn_volatile_considered_harmful:
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.
.. include:: ../disclaimer-zh_CN.rst
Maintainer: Jonathan Corbet <corbet@lwn.net>
Chinese maintainer: Bryan Wu <bryan.wu@analog.com>
---------------------------------------------------------------------
Documentation/process/volatile-considered-harmful.rst 的中文翻译
:Original: :ref:`Documentation/process/volatile-considered-harmful.rst
<volatile_considered_harmful>`
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者
译存在问题,请联系中文版维护者::
英文版维护者: 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>
以下为正文
---------------------------------------------------------------------
英文版维护者: 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>
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
为什么不应该使用“volatile”类型
------------------------------
==============================
C程序员通常认为volatile表示某个变量可以在当前执行的线程之外被改变;因此,在内核
中用到共享数据结构时,常常会有C程序员喜欢使用volatile这类变量。换句话说,他们经
......@@ -41,7 +34,7 @@ C程序员通常认为volatile表示某个变量可以在当前执行的线程
必要再使用volatile。如果仍然必须使用volatile,那么几乎可以肯定在代码的某处有一
个bug。在正确设计的内核代码中,volatile能带来的仅仅是使事情变慢。
思考一下这段典型的内核代码
思考一下这段典型的内核代码::
spin_lock(&the_lock);
do_something_on(&shared_data);
......@@ -66,7 +59,7 @@ volatile的存储类型最初是为那些内存映射的I/O寄存器而定义。
是必需的。
另一种引起用户可能使用volatile的情况是当处理器正忙着等待一个变量的值。正确执行一
个忙等待的方法是
个忙等待的方法是::
while (my_variable != what_i_want)
cpu_relax();
......
......@@ -6,7 +6,7 @@ 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>
Chinese maintainer: Li Yang <leoyang.li@nxp.com>
---------------------------------------------------------------------
Documentation/dev-tools/sparse.rst 的中文翻译
......@@ -14,8 +14,8 @@ Documentation/dev-tools/sparse.rst 的中文翻译
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题,请联系中文版维护者。
中文版维护者: 李阳 Li Yang <leo@zh-kernel.org>
中文版翻译者: 李阳 Li Yang <leo@zh-kernel.org>
中文版维护者: 李阳 Li Yang <leoyang.li@nxp.com>
中文版翻译者: 李阳 Li Yang <leoyang.li@nxp.com>
以下为正文
......
=========================
UNALIGNED MEMORY ACCESSES
Unaligned Memory Accesses
=========================
:Author: Daniel Drake <dsd@gentoo.org>,
......
......@@ -123,9 +123,9 @@ In precedence order, they are:
to userland as the errno without executing the system call.
``SECCOMP_RET_USER_NOTIF``:
Results in a ``struct seccomp_notif`` message sent on the userspace
notification fd, if it is attached, or ``-ENOSYS`` if it is not. See below
on discussion of how to handle user notifications.
Results in a ``struct seccomp_notif`` message sent on the userspace
notification fd, if it is attached, or ``-ENOSYS`` if it is not. See
below on discussion of how to handle user notifications.
``SECCOMP_RET_TRACE``:
When returned, this value will cause the kernel to attempt to
......@@ -133,7 +133,7 @@ In precedence order, they are:
call. If there is no tracer present, ``-ENOSYS`` is returned to
userland and the system call is not executed.
A tracer will be notified if it requests ``PTRACE_O_TRACESECCOM``P
A tracer will be notified if it requests ``PTRACE_O_TRACESECCOMP``
using ``ptrace(PTRACE_SETOPTIONS)``. The tracer will be notified
of a ``PTRACE_EVENT_SECCOMP`` and the ``SECCOMP_RET_DATA`` portion of
the BPF program return value will be available to the tracer
......
Video Output Switcher Control
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Video Output Switcher Control
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2006 luming.yu@intel.com
2006 luming.yu@intel.com
The output sysfs class driver provides an abstract video output layer that
can be used to hook platform specific methods to enable/disable video output
device through common sysfs interface. For example, on my IBM ThinkPad T42
laptop, The ACPI video driver registered its output devices and read/write
method for 'state' with output sysfs class. The user interface under sysfs is:
method for 'state' with output sysfs class. The user interface under sysfs is::
linux:/sys/class/video_output # tree .
.
|-- CRT0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
|-- DVI0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
|-- LCD0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
`-- TV0
|-- device -> ../../../devices/pci0000:00/0000:00:01.0
|-- state
|-- subsystem -> ../../../class/video_output
`-- uevent
linux:/sys/class/video_output # tree .
.
|-- CRT0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
|-- DVI0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
|-- LCD0
| |-- device -> ../../../devices/pci0000:00/0000:00:01.0
| |-- state
| |-- subsystem -> ../../../class/video_output
| `-- uevent
`-- TV0
|-- device -> ../../../devices/pci0000:00/0000:00:01.0
|-- state
|-- subsystem -> ../../../class/video_output
`-- uevent
......@@ -85,10 +85,10 @@ Reservation Map Location (Private or Shared)
A huge page mapping or segment is either private or shared. If private,
it is typically only available to a single address space (task). If shared,
it can be mapped into multiple address spaces (tasks). The location and
semantics of the reservation map is significantly different for two types
semantics of the reservation map is significantly different for the two types
of mappings. Location differences are:
- For private mappings, the reservation map hangs off the the VMA structure.
- For private mappings, the reservation map hangs off the VMA structure.
Specifically, vma->vm_private_data. This reserve map is created at the
time the mapping (mmap(MAP_PRIVATE)) is created.
- For shared mappings, the reservation map hangs off the inode. Specifically,
......@@ -109,15 +109,15 @@ These operations result in a call to the routine hugetlb_reserve_pages()::
struct vm_area_struct *vma,
vm_flags_t vm_flags)
The first thing hugetlb_reserve_pages() does is check for the NORESERVE
The first thing hugetlb_reserve_pages() does is check if the NORESERVE
flag was specified in either the shmget() or mmap() call. If NORESERVE
was specified, then this routine returns immediately as no reservation
was specified, then this routine returns immediately as no reservations
are desired.
The arguments 'from' and 'to' are huge page indices into the mapping or
underlying file. For shmget(), 'from' is always 0 and 'to' corresponds to
the length of the segment/mapping. For mmap(), the offset argument could
be used to specify the offset into the underlying file. In such a case
be used to specify the offset into the underlying file. In such a case,
the 'from' and 'to' arguments have been adjusted by this offset.
One of the big differences between PRIVATE and SHARED mappings is the way
......@@ -138,7 +138,8 @@ to indicate this VMA owns the reservations.
The reservation map is consulted to determine how many huge page reservations
are needed for the current mapping/segment. For private mappings, this is
always the value (to - from). However, for shared mappings it is possible that some reservations may already exist within the range (to - from). See the
always the value (to - from). However, for shared mappings it is possible that
some reservations may already exist within the range (to - from). See the
section :ref:`Reservation Map Modifications <resv_map_modifications>`
for details on how this is accomplished.
......@@ -165,7 +166,7 @@ these counters.
If there were enough free huge pages and the global count resv_huge_pages
was adjusted, then the reservation map associated with the mapping is
modified to reflect the reservations. In the case of a shared mapping, a
file_region will exist that includes the range 'from' 'to'. For private
file_region will exist that includes the range 'from' - 'to'. For private
mappings, no modifications are made to the reservation map as lack of an
entry indicates a reservation exists.
......@@ -239,7 +240,7 @@ subpool accounting when the page is freed.
The routine vma_commit_reservation() is then called to adjust the reserve
map based on the consumption of the reservation. In general, this involves
ensuring the page is represented within a file_region structure of the region
map. For shared mappings where the the reservation was present, an entry
map. For shared mappings where the reservation was present, an entry
in the reserve map already existed so no change is made. However, if there
was no reservation in a shared mapping or this was a private mapping a new
entry must be created.
......
......@@ -37,6 +37,7 @@ descriptions of data structures and algorithms.
hwpoison
hugetlbfs_reserv
ksm
memory-model
mmu_notifier
numa
overcommit-accounting
......
.. SPDX-License-Identifier: GPL-2.0
.. _physical_memory_model:
=====================
Physical Memory Model
=====================
Physical memory in a system may be addressed in different ways. The
simplest case is when the physical memory starts at address 0 and
spans a contiguous range up to the maximal address. It could be,
however, that this range contains small holes that are not accessible
for the CPU. Then there could be several contiguous ranges at
completely distinct addresses. And, don't forget about NUMA, where
different memory banks are attached to different CPUs.
Linux abstracts this diversity using one of the three memory models:
FLATMEM, DISCONTIGMEM and SPARSEMEM. Each architecture defines what
memory models it supports, what the default memory model is and
whether it is possible to manually override that default.
.. note::
At time of this writing, DISCONTIGMEM is considered deprecated,
although it is still in use by several architectures.
All the memory models track the status of physical page frames using
:c:type:`struct page` arranged in one or more arrays.
Regardless of the selected memory model, there exists one-to-one
mapping between the physical page frame number (PFN) and the
corresponding `struct page`.
Each memory model defines :c:func:`pfn_to_page` and :c:func:`page_to_pfn`
helpers that allow the conversion from PFN to `struct page` and vice
versa.
FLATMEM
=======
The simplest memory model is FLATMEM. This model is suitable for
non-NUMA systems with contiguous, or mostly contiguous, physical
memory.
In the FLATMEM memory model, there is a global `mem_map` array that
maps the entire physical memory. For most architectures, the holes
have entries in the `mem_map` array. The `struct page` objects
corresponding to the holes are never fully initialized.
To allocate the `mem_map` array, architecture specific setup code
should call :c:func:`free_area_init_node` function or its convenience
wrapper :c:func:`free_area_init`. Yet, the mappings array is not
usable until the call to :c:func:`memblock_free_all` that hands all
the memory to the page allocator.
If an architecture enables `CONFIG_ARCH_HAS_HOLES_MEMORYMODEL` option,
it may free parts of the `mem_map` array that do not cover the
actual physical pages. In such case, the architecture specific
:c:func:`pfn_valid` implementation should take the holes in the
`mem_map` into account.
With FLATMEM, the conversion between a PFN and the `struct page` is
straightforward: `PFN - ARCH_PFN_OFFSET` is an index to the
`mem_map` array.
The `ARCH_PFN_OFFSET` defines the first page frame number for
systems with physical memory starting at address different from 0.
DISCONTIGMEM
============
The DISCONTIGMEM model treats the physical memory as a collection of
`nodes` similarly to how Linux NUMA support does. For each node Linux
constructs an independent memory management subsystem represented by
`struct pglist_data` (or `pg_data_t` for short). Among other
things, `pg_data_t` holds the `node_mem_map` array that maps
physical pages belonging to that node. The `node_start_pfn` field of
`pg_data_t` is the number of the first page frame belonging to that
node.
The architecture setup code should call :c:func:`free_area_init_node` for
each node in the system to initialize the `pg_data_t` object and its
`node_mem_map`.
Every `node_mem_map` behaves exactly as FLATMEM's `mem_map` -
every physical page frame in a node has a `struct page` entry in the
`node_mem_map` array. When DISCONTIGMEM is enabled, a portion of the
`flags` field of the `struct page` encodes the node number of the
node hosting that page.
The conversion between a PFN and the `struct page` in the
DISCONTIGMEM model became slightly more complex as it has to determine
which node hosts the physical page and which `pg_data_t` object
holds the `struct page`.
Architectures that support DISCONTIGMEM provide :c:func:`pfn_to_nid`
to convert PFN to the node number. The opposite conversion helper
:c:func:`page_to_nid` is generic as it uses the node number encoded in
page->flags.
Once the node number is known, the PFN can be used to index
appropriate `node_mem_map` array to access the `struct page` and
the offset of the `struct page` from the `node_mem_map` plus
`node_start_pfn` is the PFN of that page.
SPARSEMEM
=========
SPARSEMEM is the most versatile memory model available in Linux and it
is the only memory model that supports several advanced features such
as hot-plug and hot-remove of the physical memory, alternative memory
maps for non-volatile memory devices and deferred initialization of
the memory map for larger systems.
The SPARSEMEM model presents the physical memory as a collection of
sections. A section is represented with :c:type:`struct mem_section`
that contains `section_mem_map` that is, logically, a pointer to an
array of struct pages. However, it is stored with some other magic
that aids the sections management. The section size and maximal number
of section is specified using `SECTION_SIZE_BITS` and
`MAX_PHYSMEM_BITS` constants defined by each architecture that
supports SPARSEMEM. While `MAX_PHYSMEM_BITS` is an actual width of a
physical address that an architecture supports, the
`SECTION_SIZE_BITS` is an arbitrary value.
The maximal number of sections is denoted `NR_MEM_SECTIONS` and
defined as
.. math::
NR\_MEM\_SECTIONS = 2 ^ {(MAX\_PHYSMEM\_BITS - SECTION\_SIZE\_BITS)}
The `mem_section` objects are arranged in a two-dimensional array
called `mem_sections`. The size and placement of this array depend
on `CONFIG_SPARSEMEM_EXTREME` and the maximal possible number of
sections:
* When `CONFIG_SPARSEMEM_EXTREME` is disabled, the `mem_sections`
array is static and has `NR_MEM_SECTIONS` rows. Each row holds a
single `mem_section` object.
* When `CONFIG_SPARSEMEM_EXTREME` is enabled, the `mem_sections`
array is dynamically allocated. Each row contains PAGE_SIZE worth of
`mem_section` objects and the number of rows is calculated to fit
all the memory sections.
The architecture setup code should call :c:func:`memory_present` for
each active memory range or use :c:func:`memblocks_present` or
:c:func:`sparse_memory_present_with_active_regions` wrappers to
initialize the memory sections. Next, the actual memory maps should be
set up using :c:func:`sparse_init`.
With SPARSEMEM there are two possible ways to convert a PFN to the
corresponding `struct page` - a "classic sparse" and "sparse
vmemmap". The selection is made at build time and it is determined by
the value of `CONFIG_SPARSEMEM_VMEMMAP`.
The classic sparse encodes the section number of a page in page->flags
and uses high bits of a PFN to access the section that maps that page
frame. Inside a section, the PFN is the index to the array of pages.
The sparse vmemmap uses a virtually mapped memory map to optimize
pfn_to_page and page_to_pfn operations. There is a global `struct
page *vmemmap` pointer that points to a virtually contiguous array of
`struct page` objects. A PFN is an index to that array and the the
offset of the `struct page` from `vmemmap` is the PFN of that
page.
To use vmemmap, an architecture has to reserve a range of virtual
addresses that will map the physical pages containing the memory
map and make sure that `vmemmap` points to that range. In addition,
the architecture should implement :c:func:`vmemmap_populate` method
that will allocate the physical memory and create page tables for the
virtual memory map. If an architecture does not have any special
requirements for the vmemmap mappings, it can use default
:c:func:`vmemmap_populate_basepages` provided by the generic memory
management.
The virtually mapped memory map allows storing `struct page` objects
for persistent memory devices in pre-allocated storage on those
devices. This storage is represented with :c:type:`struct vmem_altmap`
that is eventually passed to vmemmap_populate() through a long chain
of function calls. The vmemmap_populate() implementation may use the
`vmem_altmap` along with :c:func:`altmap_alloc_block_buf` helper to
allocate memory map on the persistent memory device.
......@@ -109,8 +109,8 @@ System administrators and application designers can restrict a task's migration
to improve NUMA locality using various CPU affinity command line interfaces,
such as taskset(1) and numactl(1), and program interfaces such as
sched_setaffinity(2). Further, one can modify the kernel's default local
allocation behavior using Linux NUMA memory policy.
[see Documentation/admin-guide/mm/numa_memory_policy.rst.]
allocation behavior using Linux NUMA memory policy. [see
:ref:`Documentation/admin-guide/mm/numa_memory_policy.rst <numa_memory_policy>`].
System administrators can restrict the CPUs and nodes' memories that a non-
privileged user can specify in the scheduling or NUMA commands and functions
......
......@@ -4,8 +4,9 @@
Transparent Hugepage Support
============================
This document describes design principles Transparent Hugepage (THP)
Support and its interaction with other parts of the memory management.
This document describes design principles for Transparent Hugepage (THP)
support and its interaction with other parts of the memory management
system.
Design principles
=================
......@@ -37,31 +38,25 @@ get_user_pages and follow_page
get_user_pages and follow_page if run on a hugepage, will return the
head or tail pages as usual (exactly as they would do on
hugetlbfs). Most gup users will only care about the actual physical
hugetlbfs). Most GUP users will only care about the actual physical
address of the page and its temporary pinning to release after the I/O
is complete, so they won't ever notice the fact the page is huge. But
if any driver is going to mangle over the page structure of the tail
page (like for checking page->mapping or other bits that are relevant
for the head page and not the tail page), it should be updated to jump
to check head page instead. Taking reference on any head/tail page would
prevent page from being split by anyone.
to check head page instead. Taking a reference on any head/tail page would
prevent the page from being split by anyone.
.. note::
these aren't new constraints to the GUP API, and they match the
same constrains that applies to hugetlbfs too, so any driver capable
same constraints that apply to hugetlbfs too, so any driver capable
of handling GUP on hugetlbfs will also work fine on transparent
hugepage backed mappings.
In case you can't handle compound pages if they're returned by
follow_page, the FOLL_SPLIT bit can be specified as parameter to
follow_page, the FOLL_SPLIT bit can be specified as a parameter to
follow_page, so that it will split the hugepages before returning
them. Migration for example passes FOLL_SPLIT as parameter to
follow_page because it's not hugepage aware and in fact it can't work
at all on hugetlbfs (but it instead works fine on transparent
hugepages thanks to FOLL_SPLIT). migration simply can't deal with
hugepages being returned (as it's not only checking the pfn of the
page and pinning it during the copy but it pretends to migrate the
memory in regular page sizes and with regular pte/pmd mappings).
them.
Graceful fallback
=================
......@@ -72,11 +67,11 @@ pmd_offset. It's trivial to make the code transparent hugepage aware
by just grepping for "pmd_offset" and adding split_huge_pmd where
missing after pmd_offset returns the pmd. Thanks to the graceful
fallback design, with a one liner change, you can avoid to write
hundred if not thousand of lines of complex code to make your code
hundreds if not thousands of lines of complex code to make your code
hugepage aware.
If you're not walking pagetables but you run into a physical hugepage
but you can't handle it natively in your code, you can split it by
that you can't handle natively in your code, you can split it by
calling split_huge_page(page). This is what the Linux VM does before
it tries to swapout the hugepage for example. split_huge_page() can fail
if the page is pinned and you must handle this correctly.
......@@ -103,18 +98,18 @@ split_huge_page() or split_huge_pmd() has a cost.
To make pagetable walks huge pmd aware, all you need to do is to call
pmd_trans_huge() on the pmd returned by pmd_offset. You must hold the
mmap_sem in read (or write) mode to be sure an huge pmd cannot be
mmap_sem in read (or write) mode to be sure a huge pmd cannot be
created from under you by khugepaged (khugepaged collapse_huge_page
takes the mmap_sem in write mode in addition to the anon_vma lock). If
pmd_trans_huge returns false, you just fallback in the old code
paths. If instead pmd_trans_huge returns true, you have to take the
page table lock (pmd_lock()) and re-run pmd_trans_huge. Taking the
page table lock will prevent the huge pmd to be converted into a
page table lock will prevent the huge pmd being converted into a
regular pmd from under you (split_huge_pmd can run in parallel to the
pagetable walk). If the second pmd_trans_huge returns false, you
should just drop the page table lock and fallback to the old code as
before. Otherwise you can proceed to process the huge pmd and the
hugepage natively. Once finished you can drop the page table lock.
before. Otherwise, you can proceed to process the huge pmd and the
hugepage natively. Once finished, you can drop the page table lock.
Refcounts and transparent huge pages
====================================
......@@ -122,61 +117,61 @@ Refcounts and transparent huge pages
Refcounting on THP is mostly consistent with refcounting on other compound
pages:
- get_page()/put_page() and GUP operate in head page's ->_refcount.
- get_page()/put_page() and GUP operate on head page's ->_refcount.
- ->_refcount in tail pages is always zero: get_page_unless_zero() never
succeed on tail pages.
succeeds on tail pages.
- map/unmap of the pages with PTE entry increment/decrement ->_mapcount
on relevant sub-page of the compound page.
- map/unmap of the whole compound page accounted in compound_mapcount
- map/unmap of the whole compound page is accounted for in compound_mapcount
(stored in first tail page). For file huge pages, we also increment
->_mapcount of all sub-pages in order to have race-free detection of
last unmap of subpages.
PageDoubleMap() indicates that the page is *possibly* mapped with PTEs.
For anonymous pages PageDoubleMap() also indicates ->_mapcount in all
For anonymous pages, PageDoubleMap() also indicates ->_mapcount in all
subpages is offset up by one. This additional reference is required to
get race-free detection of unmap of subpages when we have them mapped with
both PMDs and PTEs.
This is optimization required to lower overhead of per-subpage mapcount
tracking. The alternative is alter ->_mapcount in all subpages on each
This optimization is required to lower the overhead of per-subpage mapcount
tracking. The alternative is to alter ->_mapcount in all subpages on each
map/unmap of the whole compound page.
For anonymous pages, we set PG_double_map when a PMD of the page got split
for the first time, but still have PMD mapping. The additional references
go away with last compound_mapcount.
For anonymous pages, we set PG_double_map when a PMD of the page is split
for the first time, but still have a PMD mapping. The additional references
go away with the last compound_mapcount.
File pages get PG_double_map set on first map of the page with PTE and
goes away when the page gets evicted from page cache.
File pages get PG_double_map set on the first map of the page with PTE and
goes away when the page gets evicted from the page cache.
split_huge_page internally has to distribute the refcounts in the head
page to the tail pages before clearing all PG_head/tail bits from the page
structures. It can be done easily for refcounts taken by page table
entries. But we don't have enough information on how to distribute any
entries, but we don't have enough information on how to distribute any
additional pins (i.e. from get_user_pages). split_huge_page() fails any
requests to split pinned huge page: it expects page count to be equal to
sum of mapcount of all sub-pages plus one (split_huge_page caller must
have reference for head page).
requests to split pinned huge pages: it expects page count to be equal to
the sum of mapcount of all sub-pages plus one (split_huge_page caller must
have a reference to the head page).
split_huge_page uses migration entries to stabilize page->_refcount and
page->_mapcount of anonymous pages. File pages just got unmapped.
page->_mapcount of anonymous pages. File pages just get unmapped.
We safe against physical memory scanners too: the only legitimate way
scanner can get reference to a page is get_page_unless_zero().
We are safe against physical memory scanners too: the only legitimate way
a scanner can get a reference to a page is get_page_unless_zero().
All tail pages have zero ->_refcount until atomic_add(). This prevents the
scanner from getting a reference to the tail page up to that point. After the
atomic_add() we don't care about the ->_refcount value. We already known how
atomic_add() we don't care about the ->_refcount value. We already know how
many references should be uncharged from the head page.
For head page get_page_unless_zero() will succeed and we don't mind. It's
clear where reference should go after split: it will stay on head page.
clear where references should go after split: it will stay on the head page.
Note that split_huge_pmd() doesn't have any limitation on refcounting:
Note that split_huge_pmd() doesn't have any limitations on refcounting:
pmd can be split at any point and never fails.
Partial unmap and deferred_split_huge_page()
......@@ -188,10 +183,10 @@ in page_remove_rmap() and queue the THP for splitting if memory pressure
comes. Splitting will free up unused subpages.
Splitting the page right away is not an option due to locking context in
the place where we can detect partial unmap. It's also might be
the place where we can detect partial unmap. It also might be
counterproductive since in many cases partial unmap happens during exit(2) if
a THP crosses a VMA boundary.
Function deferred_split_huge_page() is used to queue page for splitting.
The function deferred_split_huge_page() is used to queue a page for splitting.
The splitting itself will happen when we get memory pressure via shrinker
interface.
......@@ -61,6 +61,10 @@ Protocol 2.12: (Kernel 3.8) Added the xloadflags field and extension fields
to struct boot_params for loading bzImage and ramdisk
above 4G in 64bit.
Protocol 2.13: (Kernel 3.14) Support 32- and 64-bit flags being set in
xloadflags to support booting a 64-bit kernel from 32-bit
EFI
**** MEMORY LAYOUT
The traditional memory map for the kernel loader, used for Image or
......
Valid-License-Identifier: Apache-2.0
SPDX-URL: https://spdx.org/licenses/Apache-2.0.html
Usage-Guide:
Do NOT use. The Apache-2.0 is not GPL2 compatible. It may only be used
for dual-licensed files where the other license is GPL2 compatible.
If you end up using this it MUST be used together with a GPL2 compatible
license using "OR".
To use the Apache License version 2.0 put the following SPDX tag/value
pair into a comment according to the placement guidelines in the
licensing rules documentation:
......
Valid-License-Identifier: CDDL-1.0
SPDX-URL: https://spdx.org/licenses/CDDL-1.0.html
Usage-Guide:
Do NOT use. The CDDL-1.0 is not GPL compatible. It may only be used for
dual-licensed files where the other license is GPL compatible.
Do NOT use. The CDDL-1.0 is not GPL2 compatible. It may only be used for
dual-licensed files where the other license is GPL2 compatible.
If you end up using this it MUST be used together with a GPL2 compatible
license using "OR".
To use the Common Development and Distribution License 1.0 put the
......
Valid-License-Identifier: MPL-1.1
SPDX-URL: https://spdx.org/licenses/MPL-1.1.html
Usage-Guide:
Do NOT use. The MPL-1.1 is not GPL2 compatible. It may only be used for
dual-licensed files where the other license is GPL2 compatible.
If you end up using this it MUST be used together with a GPL2 compatible
license using "OR".
To use the Mozilla Public License version 1.1 put the following SPDX
tag/value pair into a comment according to the placement guidelines in
the licensing rules documentation:
......
......@@ -3737,8 +3737,8 @@ F: scripts/checkpatch.pl
CHINESE DOCUMENTATION
M: Harry Wei <harryxiyou@gmail.com>
M: Alex Shi <alex.shi@linux.alibaba.com>
L: xiyoulinuxkernelgroup@googlegroups.com (subscribers-only)
L: linux-kernel@zh-kernel.org (moderated for non-subscribers)
S: Maintained
F: Documentation/translations/zh_CN/
......
......@@ -101,7 +101,7 @@ init_waitqueue_func_entry(struct wait_queue_entry *wq_entry, wait_queue_func_t f
* lead to sporadic and non-obvious failure.
*
* Use either while holding wait_queue_head::lock or when used for wakeups
* with an extra smp_mb() like:
* with an extra smp_mb() like::
*
* CPU0 - waker CPU1 - waiter
*
......
......@@ -2687,6 +2687,24 @@ sub process {
} else {
$signatures{$sig_nospace} = 1;
}
# Check Co-developed-by: immediately followed by Signed-off-by: with same name and email
if ($sign_off =~ /^co-developed-by:$/i) {
if ($email eq $author) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: should not be used to attribute nominal patch author '$author'\n" . "$here\n" . $rawline);
}
if (!defined $lines[$linenr]) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline);
} elsif ($rawlines[$linenr] !~ /^\s*signed-off-by:\s*(.*)/i) {
WARN("BAD_SIGN_OFF",
"Co-developed-by: must be immediately followed by Signed-off-by:\n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
} elsif ($1 ne $email) {
WARN("BAD_SIGN_OFF",
"Co-developed-by and Signed-off-by: name/email do not match \n" . "$here\n" . $rawline . "\n" .$rawlines[$linenr]);
}
}
}
# Check email subject for common tools that don't need to be mentioned
......
......@@ -30,6 +30,34 @@ print "Finding broken references. This may take a while... " if ($fix);
my %broken_ref;
my $doc_fix = 0;
open IN, "git grep ':doc:\`' Documentation/|"
or die "Failed to run git grep";
while (<IN>) {
next if (!m,^([^:]+):.*\:doc\:\`([^\`]+)\`,);
my $d = $1;
my $doc_ref = $2;
my $f = $doc_ref;
$d =~ s,(.*/).*,$1,;
$f =~ s,.*\<([^\>]+)\>,$1,;
$f ="$d$f.rst";
next if (grep -e, glob("$f"));
if ($fix && !$doc_fix) {
print STDERR "\nWARNING: Currently, can't fix broken :doc:`` fields\n";
}
$doc_fix++;
print STDERR "$f: :doc:`$doc_ref`\n";
}
close IN;
open IN, "git grep 'Documentation/'|"
or die "Failed to run git grep";
while (<IN>) {
......@@ -38,6 +66,9 @@ while (<IN>) {
my $f = $1;
my $ln = $2;
# On linux-next, discard the Next/ directory
next if ($f =~ m,^Next/,);
# Makefiles and scripts contain nasty expressions to parse docs
next if ($f =~ m/Makefile/ || $f =~ m/\.sh$/);
......@@ -100,6 +131,7 @@ while (<IN>) {
}
}
}
close IN;
exit 0 if (!$fix);
......
......@@ -532,6 +532,7 @@ sub check_needs()
check_program("dot", 1);
check_program("convert", 1);
check_program("rsvg-convert", 1) if ($pdf);
check_program("latexmk", 1) if ($pdf);
check_distros();
......
......@@ -111,7 +111,7 @@ c) Higher live patching compatibility rate
be detectable). Objtool makes that possible.
For more details, see the livepatch documentation in the Linux kernel
source tree at Documentation/livepatch/livepatch.txt.
source tree at Documentation/livepatch/livepatch.rst.
Rules
-----
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment