forked from Minki/linux
There's not a huge amount of activity in the docs tree this time around,
but a few significant changes even so: - A complete rewriting of the top-level index.rst file, which mostly reflects itself in a redone top page in the HTML-rendered docs. The hope is that the new organization will be a friendlier starting point for both users and developers. - Some math-rendering improvements. - A coding-style.rst update on the use of BUG() and WARN() - A big maintainer-PHP guide update. - Some code-of-conduct updates - More Chinese translation work Plus the usual pile of typo fixes, corrections, and updates. -----BEGIN PGP SIGNATURE----- iQFDBAABCAAtFiEEIw+MvkEiF49krdp9F0NaE2wMflgFAmM7BksPHGNvcmJldEBs d24ubmV0AAoJEBdDWhNsDH5Y8i4H/ihd1ppgVYy1yvFL3L1KkcsNyt3bFUa6hide qmkhqpzjsNmbTOaW19Y6epCzRzvxG7M9hzztIewt1BhRDvgRC8GaQNNRw/IBs0B6 kprisINC2/ap4JjCroYWepfd+H8NSiVxqtd8hVSMWDSh2cK9vw0qVqQq59I+gght 64pA4F2nPO6bamZzAELTdWRj0ITL1A/V/jYj+T074B094arc4HyekIQ5Jn9GTCmt jFBH9yxAb3l8K7KgzH7FgxKY/an0HxKDh4Cnx2Jv+dcocgCwy1iXCuyEZbFd9GEB UyhPcCyrIe/I2B9U9LrqLvXA8LW7jwE+MZMqZpaRkxcIdE2gEFQ= =M7tR -----END PGP SIGNATURE----- Merge tag 'docs-6.1' of git://git.lwn.net/linux Pull documentation updates from Jonathan Corbet: "There's not a huge amount of activity in the docs tree this time around, but a few significant changes even so: - A complete rewriting of the top-level index.rst file, which mostly reflects itself in a redone top page in the HTML-rendered docs. The hope is that the new organization will be a friendlier starting point for both users and developers. - Some math-rendering improvements. - A coding-style.rst update on the use of BUG() and WARN() - A big maintainer-PHP guide update. - Some code-of-conduct updates - More Chinese translation work Plus the usual pile of typo fixes, corrections, and updates" * tag 'docs-6.1' of git://git.lwn.net/linux: (66 commits) checkpatch: warn on usage of VM_BUG_ON() and other BUG variants coding-style.rst: document BUG() and WARN() rules ("do not crash the kernel") Documentation: devres: add missing IO helper Documentation: devres: update IRQ helper Documentation/mm: modify page_referenced to folio_referenced Documentation/CoC: Reflect current CoC interpretation and practices docs/doc-guide: Add documentation on SPHINX_IMGMATH docs: process/5.Posting.rst: clarify use of Reported-by: tag docs, kprobes: Fix the wrong location of Kprobes docs: add a man-pages link to the front page docs: put atomic*.txt and memory-barriers.txt into the core-api book docs: move asm-annotations.rst into core-api docs: remove some index.rst cruft docs: reconfigure the HTML left column docs: Rewrite the front page docs: promote the title of process/index.rst Documentation: devres: add missing SPI helper Documentation: devres: add missing PINCTRL helpers docs: hugetlbpage.rst: fix a typo of hugepage size docs/zh_CN: Add new translation of admin-guide/bootconfig.rst ...
This commit is contained in:
commit
f3dfe925f9
@ -3,7 +3,7 @@ Date: May 2011
|
|||||||
KernelVersion: 3.0
|
KernelVersion: 3.0
|
||||||
Contact: Rafał Miłecki <zajec5@gmail.com>
|
Contact: Rafał Miłecki <zajec5@gmail.com>
|
||||||
Description:
|
Description:
|
||||||
Each BCMA core has it's manufacturer id. See
|
Each BCMA core has its manufacturer id. See
|
||||||
include/linux/bcma/bcma.h for possible values.
|
include/linux/bcma/bcma.h for possible values.
|
||||||
|
|
||||||
What: /sys/bus/bcma/devices/.../id
|
What: /sys/bus/bcma/devices/.../id
|
||||||
|
@ -31,7 +31,7 @@ Description: 'FCoE Controller' instances on the fcoe bus.
|
|||||||
1) Write interface name to ctlr_create 2) Configure the FCoE
|
1) Write interface name to ctlr_create 2) Configure the FCoE
|
||||||
Controller (ctlr_X) 3) Enable the FCoE Controller to begin
|
Controller (ctlr_X) 3) Enable the FCoE Controller to begin
|
||||||
discovery and login. The FCoE Controller is destroyed by
|
discovery and login. The FCoE Controller is destroyed by
|
||||||
writing it's name, i.e. ctlr_X to the ctlr_delete file.
|
writing its name, i.e. ctlr_X to the ctlr_delete file.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ Description:
|
|||||||
on the signal from which time of flight measurements are
|
on the signal from which time of flight measurements are
|
||||||
taken.
|
taken.
|
||||||
The appropriate values to take is dependent on both the
|
The appropriate values to take is dependent on both the
|
||||||
sensor and it's operating environment:
|
sensor and its operating environment:
|
||||||
* as3935 (0-31 range)
|
* as3935 (0-31 range)
|
||||||
18 = indoors (default)
|
18 = indoors (default)
|
||||||
14 = outdoors
|
14 = outdoors
|
||||||
|
@ -296,7 +296,7 @@ Description: Processor frequency boosting control
|
|||||||
|
|
||||||
This switch controls the boost setting for the whole system.
|
This switch controls the boost setting for the whole system.
|
||||||
Boosting allows the CPU and the firmware to run at a frequency
|
Boosting allows the CPU and the firmware to run at a frequency
|
||||||
beyond it's nominal limit.
|
beyond its nominal limit.
|
||||||
|
|
||||||
More details can be found in
|
More details can be found in
|
||||||
Documentation/admin-guide/pm/cpufreq.rst
|
Documentation/admin-guide/pm/cpufreq.rst
|
||||||
|
@ -2,8 +2,8 @@ What: /sys/bus/platform/devices/ci_hdrc.0/role
|
|||||||
Date: Mar 2017
|
Date: Mar 2017
|
||||||
Contact: Peter Chen <peter.chen@nxp.com>
|
Contact: Peter Chen <peter.chen@nxp.com>
|
||||||
Description:
|
Description:
|
||||||
It returns string "gadget" or "host" when read it, it indicates
|
When read, it returns string "gadget" or "host", indicating
|
||||||
current controller role.
|
the current controller role.
|
||||||
|
|
||||||
It will do role switch when write "gadget" or "host" to it.
|
It will do role switch when "gadget" or "host" is written to it.
|
||||||
Only controller at dual-role configuration supports writing.
|
Only controller at dual-role configuration supports writing.
|
||||||
|
@ -152,7 +152,7 @@ Description:
|
|||||||
case further investigation is required to determine which
|
case further investigation is required to determine which
|
||||||
device is causing the problem. Note that genuine RTC clock
|
device is causing the problem. Note that genuine RTC clock
|
||||||
values (such as when pm_trace has not been used), can still
|
values (such as when pm_trace has not been used), can still
|
||||||
match a device and output it's name here.
|
match a device and output its name here.
|
||||||
|
|
||||||
What: /sys/power/pm_async
|
What: /sys/power/pm_async
|
||||||
Date: January 2009
|
Date: January 2009
|
||||||
|
@ -486,6 +486,6 @@ over a rather long period of time, but improvements are always welcome!
|
|||||||
So if you need to wait for both an RCU grace period and for
|
So if you need to wait for both an RCU grace period and for
|
||||||
all pre-existing call_rcu() callbacks, you will need to execute
|
all pre-existing call_rcu() callbacks, you will need to execute
|
||||||
both rcu_barrier() and synchronize_rcu(), if necessary, using
|
both rcu_barrier() and synchronize_rcu(), if necessary, using
|
||||||
something like workqueues to to execute them concurrently.
|
something like workqueues to execute them concurrently.
|
||||||
|
|
||||||
See rcubarrier.rst for more information.
|
See rcubarrier.rst for more information.
|
||||||
|
@ -61,7 +61,7 @@ checking of rcu_dereference() primitives:
|
|||||||
rcu_access_pointer(p):
|
rcu_access_pointer(p):
|
||||||
Return the value of the pointer and omit all barriers,
|
Return the value of the pointer and omit all barriers,
|
||||||
but retain the compiler constraints that prevent duplicating
|
but retain the compiler constraints that prevent duplicating
|
||||||
or coalescsing. This is useful when when testing the
|
or coalescsing. This is useful when testing the
|
||||||
value of the pointer itself, for example, against NULL.
|
value of the pointer itself, for example, against NULL.
|
||||||
|
|
||||||
The rcu_dereference_check() check expression can be any boolean
|
The rcu_dereference_check() check expression can be any boolean
|
||||||
|
@ -262,8 +262,6 @@ Compiling the kernel
|
|||||||
- Make sure you have at least gcc 5.1 available.
|
- Make sure you have at least gcc 5.1 available.
|
||||||
For more information, refer to :ref:`Documentation/process/changes.rst <changes>`.
|
For more information, refer to :ref:`Documentation/process/changes.rst <changes>`.
|
||||||
|
|
||||||
Please note that you can still run a.out user programs with this kernel.
|
|
||||||
|
|
||||||
- Do a ``make`` to create a compressed kernel image. It is also
|
- Do a ``make`` to create a compressed kernel image. It is also
|
||||||
possible to do ``make install`` if you have lilo installed to suit the
|
possible to do ``make install`` if you have lilo installed to suit the
|
||||||
kernel makefiles, but you may want to check your particular lilo setup first.
|
kernel makefiles, but you may want to check your particular lilo setup first.
|
||||||
@ -332,85 +330,10 @@ Compiling the kernel
|
|||||||
If something goes wrong
|
If something goes wrong
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
- If you have problems that seem to be due to kernel bugs, please check
|
If you have problems that seem to be due to kernel bugs, please follow the
|
||||||
the file MAINTAINERS to see if there is a particular person associated
|
instructions at 'Documentation/admin-guide/reporting-issues.rst'.
|
||||||
with the part of the kernel that you are having trouble with. If there
|
|
||||||
isn't anyone listed there, then the second best thing is to mail
|
|
||||||
them to me (torvalds@linux-foundation.org), and possibly to any other
|
|
||||||
relevant mailing-list or to the newsgroup.
|
|
||||||
|
|
||||||
- In all bug-reports, *please* tell what kernel you are talking about,
|
Hints on understanding kernel bug reports are in
|
||||||
how to duplicate the problem, and what your setup is (use your common
|
'Documentation/admin-guide/bug-hunting.rst'. More on debugging the kernel
|
||||||
sense). If the problem is new, tell me so, and if the problem is
|
with gdb is in 'Documentation/dev-tools/gdb-kernel-debugging.rst' and
|
||||||
old, please try to tell me when you first noticed it.
|
'Documentation/dev-tools/kgdb.rst'.
|
||||||
|
|
||||||
- If the bug results in a message like::
|
|
||||||
|
|
||||||
unable to handle kernel paging request at address C0000010
|
|
||||||
Oops: 0002
|
|
||||||
EIP: 0010:XXXXXXXX
|
|
||||||
eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
|
|
||||||
esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
|
|
||||||
ds: xxxx es: xxxx fs: xxxx gs: xxxx
|
|
||||||
Pid: xx, process nr: xx
|
|
||||||
xx xx xx xx xx xx xx xx xx xx
|
|
||||||
|
|
||||||
or similar kernel debugging information on your screen or in your
|
|
||||||
system log, please duplicate it *exactly*. The dump may look
|
|
||||||
incomprehensible to you, but it does contain information that may
|
|
||||||
help debugging the problem. The text above the dump is also
|
|
||||||
important: it tells something about why the kernel dumped code (in
|
|
||||||
the above example, it's due to a bad kernel pointer). More information
|
|
||||||
on making sense of the dump is in Documentation/admin-guide/bug-hunting.rst
|
|
||||||
|
|
||||||
- If you compiled the kernel with CONFIG_KALLSYMS you can send the dump
|
|
||||||
as is, otherwise you will have to use the ``ksymoops`` program to make
|
|
||||||
sense of the dump (but compiling with CONFIG_KALLSYMS is usually preferred).
|
|
||||||
This utility can be downloaded from
|
|
||||||
https://www.kernel.org/pub/linux/utils/kernel/ksymoops/ .
|
|
||||||
Alternatively, you can do the dump lookup by hand:
|
|
||||||
|
|
||||||
- In debugging dumps like the above, it helps enormously if you can
|
|
||||||
look up what the EIP value means. The hex value as such doesn't help
|
|
||||||
me or anybody else very much: it will depend on your particular
|
|
||||||
kernel setup. What you should do is take the hex value from the EIP
|
|
||||||
line (ignore the ``0010:``), and look it up in the kernel namelist to
|
|
||||||
see which kernel function contains the offending address.
|
|
||||||
|
|
||||||
To find out the kernel function name, you'll need to find the system
|
|
||||||
binary associated with the kernel that exhibited the symptom. This is
|
|
||||||
the file 'linux/vmlinux'. To extract the namelist and match it against
|
|
||||||
the EIP from the kernel crash, do::
|
|
||||||
|
|
||||||
nm vmlinux | sort | less
|
|
||||||
|
|
||||||
This will give you a list of kernel addresses sorted in ascending
|
|
||||||
order, from which it is simple to find the function that contains the
|
|
||||||
offending address. Note that the address given by the kernel
|
|
||||||
debugging messages will not necessarily match exactly with the
|
|
||||||
function addresses (in fact, that is very unlikely), so you can't
|
|
||||||
just 'grep' the list: the list will, however, give you the starting
|
|
||||||
point of each kernel function, so by looking for the function that
|
|
||||||
has a starting address lower than the one you are searching for but
|
|
||||||
is followed by a function with a higher address you will find the one
|
|
||||||
you want. In fact, it may be a good idea to include a bit of
|
|
||||||
"context" in your problem report, giving a few lines around the
|
|
||||||
interesting one.
|
|
||||||
|
|
||||||
If you for some reason cannot do the above (you have a pre-compiled
|
|
||||||
kernel image or similar), telling me as much about your setup as
|
|
||||||
possible will help. Please read
|
|
||||||
'Documentation/admin-guide/reporting-issues.rst' for details.
|
|
||||||
|
|
||||||
- Alternatively, you can use gdb on a running kernel. (read-only; i.e. you
|
|
||||||
cannot change values or set break points.) To do this, first compile the
|
|
||||||
kernel with -g; edit arch/x86/Makefile appropriately, then do a ``make
|
|
||||||
clean``. You'll also need to enable CONFIG_PROC_FS (via ``make config``).
|
|
||||||
|
|
||||||
After you've rebooted with the new kernel, do ``gdb vmlinux /proc/kcore``.
|
|
||||||
You can now use all the usual gdb commands. The command to look up the
|
|
||||||
point where your system crashed is ``l *0xXXXXXXXX``. (Replace the XXXes
|
|
||||||
with the EIP value.)
|
|
||||||
|
|
||||||
gdb'ing a non-running kernel currently fails because ``gdb`` (wrongly)
|
|
||||||
disregards the starting offset for which the kernel is compiled.
|
|
||||||
|
@ -613,6 +613,7 @@ kernel command line.
|
|||||||
eibrs enhanced IBRS
|
eibrs enhanced IBRS
|
||||||
eibrs,retpoline enhanced IBRS + Retpolines
|
eibrs,retpoline enhanced IBRS + Retpolines
|
||||||
eibrs,lfence enhanced IBRS + LFENCE
|
eibrs,lfence enhanced IBRS + LFENCE
|
||||||
|
ibrs use IBRS to protect kernel
|
||||||
|
|
||||||
Not specifying this option is equivalent to
|
Not specifying this option is equivalent to
|
||||||
spectre_v2=auto.
|
spectre_v2=auto.
|
||||||
|
@ -200,7 +200,7 @@ prb
|
|||||||
|
|
||||||
A pointer to the printk ringbuffer (struct printk_ringbuffer). This
|
A pointer to the printk ringbuffer (struct printk_ringbuffer). This
|
||||||
may be pointing to the static boot ringbuffer or the dynamically
|
may be pointing to the static boot ringbuffer or the dynamically
|
||||||
allocated ringbuffer, depending on when the the core dump occurred.
|
allocated ringbuffer, depending on when the core dump occurred.
|
||||||
Used by user-space tools to read the active kernel log buffer.
|
Used by user-space tools to read the active kernel log buffer.
|
||||||
|
|
||||||
printk_rb_static
|
printk_rb_static
|
||||||
|
@ -65,7 +65,7 @@ HugePages_Surp
|
|||||||
may be temporarily larger than the maximum number of surplus huge
|
may be temporarily larger than the maximum number of surplus huge
|
||||||
pages when the system is under memory pressure.
|
pages when the system is under memory pressure.
|
||||||
Hugepagesize
|
Hugepagesize
|
||||||
is the default hugepage size (in Kb).
|
is the default hugepage size (in kB).
|
||||||
Hugetlb
|
Hugetlb
|
||||||
is the total amount of memory (in kB), consumed by huge
|
is the total amount of memory (in kB), consumed by huge
|
||||||
pages of all sizes.
|
pages of all sizes.
|
||||||
|
@ -133,7 +133,7 @@ code field of ``BPF_END``.
|
|||||||
The byte swap instructions operate on the destination register
|
The byte swap instructions operate on the destination register
|
||||||
only and do not use a separate source register or immediate value.
|
only and do not use a separate source register or immediate value.
|
||||||
|
|
||||||
The 1-bit source operand field in the opcode is used to to select what byte
|
The 1-bit source operand field in the opcode is used to select what byte
|
||||||
order the operation convert from or to:
|
order the operation convert from or to:
|
||||||
|
|
||||||
========= ===== =================================================
|
========= ===== =================================================
|
||||||
|
@ -31,7 +31,7 @@ The map uses key of type of either ``__u64 cgroup_inode_id`` or
|
|||||||
};
|
};
|
||||||
|
|
||||||
``cgroup_inode_id`` is the inode id of the cgroup directory.
|
``cgroup_inode_id`` is the inode id of the cgroup directory.
|
||||||
``attach_type`` is the the program's attach type.
|
``attach_type`` is the program's attach type.
|
||||||
|
|
||||||
Linux 5.9 added support for type ``__u64 cgroup_inode_id`` as the key type.
|
Linux 5.9 added support for type ``__u64 cgroup_inode_id`` as the key type.
|
||||||
When this key type is used, then all attach types of the particular cgroup and
|
When this key type is used, then all attach types of the particular cgroup and
|
||||||
@ -155,7 +155,7 @@ However, the BPF program can still only associate with one map of each type
|
|||||||
``BPF_MAP_TYPE_CGROUP_STORAGE`` or more than one
|
``BPF_MAP_TYPE_CGROUP_STORAGE`` or more than one
|
||||||
``BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE``.
|
``BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE``.
|
||||||
|
|
||||||
In all versions, userspace may use the the attach parameters of cgroup and
|
In all versions, userspace may use the attach parameters of cgroup and
|
||||||
attach type pair in ``struct bpf_cgroup_storage_key`` as the key to the BPF map
|
attach type pair in ``struct bpf_cgroup_storage_key`` as the key to the BPF map
|
||||||
APIs to read or update the storage for a given attachment. For Linux 5.9
|
APIs to read or update the storage for a given attachment. For Linux 5.9
|
||||||
attach type shared storages, only the first value in the struct, cgroup inode
|
attach type shared storages, only the first value in the struct, cgroup inode
|
||||||
|
@ -15,6 +15,18 @@
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import sphinx
|
import sphinx
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
# helper
|
||||||
|
# ------
|
||||||
|
|
||||||
|
def have_command(cmd):
|
||||||
|
"""Search ``cmd`` in the ``PATH`` environment.
|
||||||
|
|
||||||
|
If found, return True.
|
||||||
|
If not found, return False.
|
||||||
|
"""
|
||||||
|
return shutil.which(cmd) is not None
|
||||||
|
|
||||||
# Get Sphinx version
|
# Get Sphinx version
|
||||||
major, minor, patch = sphinx.version_info[:3]
|
major, minor, patch = sphinx.version_info[:3]
|
||||||
@ -107,7 +119,32 @@ else:
|
|||||||
autosectionlabel_prefix_document = True
|
autosectionlabel_prefix_document = True
|
||||||
autosectionlabel_maxdepth = 2
|
autosectionlabel_maxdepth = 2
|
||||||
|
|
||||||
extensions.append("sphinx.ext.imgmath")
|
# Load math renderer:
|
||||||
|
# For html builder, load imgmath only when its dependencies are met.
|
||||||
|
# mathjax is the default math renderer since Sphinx 1.8.
|
||||||
|
have_latex = have_command('latex')
|
||||||
|
have_dvipng = have_command('dvipng')
|
||||||
|
load_imgmath = have_latex and have_dvipng
|
||||||
|
|
||||||
|
# Respect SPHINX_IMGMATH (for html docs only)
|
||||||
|
if 'SPHINX_IMGMATH' in os.environ:
|
||||||
|
env_sphinx_imgmath = os.environ['SPHINX_IMGMATH']
|
||||||
|
if 'yes' in env_sphinx_imgmath:
|
||||||
|
load_imgmath = True
|
||||||
|
elif 'no' in env_sphinx_imgmath:
|
||||||
|
load_imgmath = False
|
||||||
|
else:
|
||||||
|
sys.stderr.write("Unknown env SPHINX_IMGMATH=%s ignored.\n" % env_sphinx_imgmath)
|
||||||
|
|
||||||
|
# Always load imgmath for Sphinx <1.8 or for epub docs
|
||||||
|
load_imgmath = (load_imgmath or (major == 1 and minor < 8)
|
||||||
|
or 'epub' in sys.argv)
|
||||||
|
|
||||||
|
if load_imgmath:
|
||||||
|
extensions.append("sphinx.ext.imgmath")
|
||||||
|
math_renderer = 'imgmath'
|
||||||
|
else:
|
||||||
|
math_renderer = 'mathjax'
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ['_templates']
|
templates_path = ['_templates']
|
||||||
@ -333,7 +370,8 @@ html_static_path = ['sphinx-static']
|
|||||||
html_use_smartypants = False
|
html_use_smartypants = False
|
||||||
|
|
||||||
# Custom sidebar templates, maps document names to template names.
|
# Custom sidebar templates, maps document names to template names.
|
||||||
#html_sidebars = {}
|
# Note that the RTD theme ignores this.
|
||||||
|
html_sidebars = { '**': ['searchbox.html', 'localtoc.html', 'sourcelink.html']}
|
||||||
|
|
||||||
# Additional templates that should be rendered to pages, maps page names to
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
# template names.
|
# template names.
|
||||||
|
@ -43,10 +43,11 @@ annotated objects like this, tools can be run on them to generate more useful
|
|||||||
information. In particular, on properly annotated objects, ``objtool`` can be
|
information. In particular, on properly annotated objects, ``objtool`` can be
|
||||||
run to check and fix the object if needed. Currently, ``objtool`` can report
|
run to check and fix the object if needed. Currently, ``objtool`` can report
|
||||||
missing frame pointer setup/destruction in functions. It can also
|
missing frame pointer setup/destruction in functions. It can also
|
||||||
automatically generate annotations for :doc:`ORC unwinder <x86/orc-unwinder>`
|
automatically generate annotations for the ORC unwinder
|
||||||
|
(Documentation/x86/orc-unwinder.rst)
|
||||||
for most code. Both of these are especially important to support reliable
|
for most code. Both of these are especially important to support reliable
|
||||||
stack traces which are in turn necessary for :doc:`Kernel live patching
|
stack traces which are in turn necessary for kernel live patching
|
||||||
<livepatch/livepatch>`.
|
(Documentation/livepatch/livepatch.rst).
|
||||||
|
|
||||||
Caveat and Discussion
|
Caveat and Discussion
|
||||||
---------------------
|
---------------------
|
@ -560,7 +560,7 @@ available:
|
|||||||
* cpuhp_state_remove_instance(state, node)
|
* cpuhp_state_remove_instance(state, node)
|
||||||
* cpuhp_state_remove_instance_nocalls(state, node)
|
* cpuhp_state_remove_instance_nocalls(state, node)
|
||||||
|
|
||||||
The arguments are the same as for the the cpuhp_state_add_instance*()
|
The arguments are the same as for the cpuhp_state_add_instance*()
|
||||||
variants above.
|
variants above.
|
||||||
|
|
||||||
The functions differ in the way how the installed callbacks are treated:
|
The functions differ in the way how the installed callbacks are treated:
|
||||||
|
@ -23,6 +23,7 @@ it.
|
|||||||
printk-formats
|
printk-formats
|
||||||
printk-index
|
printk-index
|
||||||
symbol-namespaces
|
symbol-namespaces
|
||||||
|
asm-annotations
|
||||||
|
|
||||||
Data structures and low-level utilities
|
Data structures and low-level utilities
|
||||||
=======================================
|
=======================================
|
||||||
@ -44,6 +45,8 @@ Library functionality that is used throughout the kernel.
|
|||||||
this_cpu_ops
|
this_cpu_ops
|
||||||
timekeeping
|
timekeeping
|
||||||
errseq
|
errseq
|
||||||
|
wrappers/atomic_t
|
||||||
|
wrappers/atomic_bitops
|
||||||
|
|
||||||
Low level entry and exit
|
Low level entry and exit
|
||||||
========================
|
========================
|
||||||
@ -67,6 +70,7 @@ Documentation/locking/index.rst for more related documentation.
|
|||||||
local_ops
|
local_ops
|
||||||
padata
|
padata
|
||||||
../RCU/index
|
../RCU/index
|
||||||
|
wrappers/memory-barriers.rst
|
||||||
|
|
||||||
Low-level hardware management
|
Low-level hardware management
|
||||||
=============================
|
=============================
|
||||||
|
@ -71,7 +71,7 @@ variety of methods:
|
|||||||
Note that irq domain lookups must happen in contexts that are
|
Note that irq domain lookups must happen in contexts that are
|
||||||
compatible with a RCU read-side critical section.
|
compatible with a RCU read-side critical section.
|
||||||
|
|
||||||
The irq_create_mapping() function must be called *atleast once*
|
The irq_create_mapping() function must be called *at least once*
|
||||||
before any call to irq_find_mapping(), lest the descriptor will not
|
before any call to irq_find_mapping(), lest the descriptor will not
|
||||||
be allocated.
|
be allocated.
|
||||||
|
|
||||||
|
18
Documentation/core-api/wrappers/atomic_bitops.rst
Normal file
18
Documentation/core-api/wrappers/atomic_bitops.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
This is a simple wrapper to bring atomic_bitops.txt into the RST world
|
||||||
|
until such a time as that file can be converted directly.
|
||||||
|
|
||||||
|
=============
|
||||||
|
Atomic bitops
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\footnotesize
|
||||||
|
|
||||||
|
.. include:: ../../atomic_bitops.txt
|
||||||
|
:literal:
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\normalsize
|
19
Documentation/core-api/wrappers/atomic_t.rst
Normal file
19
Documentation/core-api/wrappers/atomic_t.rst
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
This is a simple wrapper to bring atomic_t.txt into the RST world
|
||||||
|
until such a time as that file can be converted directly.
|
||||||
|
|
||||||
|
============
|
||||||
|
Atomic types
|
||||||
|
============
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\footnotesize
|
||||||
|
|
||||||
|
.. include:: ../../atomic_t.txt
|
||||||
|
:literal:
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\normalsize
|
||||||
|
|
18
Documentation/core-api/wrappers/memory-barriers.rst
Normal file
18
Documentation/core-api/wrappers/memory-barriers.rst
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
This is a simple wrapper to bring memory-barriers.txt into the RST world
|
||||||
|
until such a time as that file can be converted directly.
|
||||||
|
|
||||||
|
============================
|
||||||
|
Linux kernel memory barriers
|
||||||
|
============================
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\footnotesize
|
||||||
|
|
||||||
|
.. include:: ../../memory-barriers.txt
|
||||||
|
:literal:
|
||||||
|
|
||||||
|
.. raw:: latex
|
||||||
|
|
||||||
|
\normalsize
|
@ -48,10 +48,6 @@ or ``virtualenv``, depending on how your distribution packaged Python 3.
|
|||||||
on the Sphinx version, it should be installed separately,
|
on the Sphinx version, it should be installed separately,
|
||||||
with ``pip install sphinx_rtd_theme``.
|
with ``pip install sphinx_rtd_theme``.
|
||||||
|
|
||||||
#) Some ReST pages contain math expressions. Due to the way Sphinx works,
|
|
||||||
those expressions are written using LaTeX notation. It needs texlive
|
|
||||||
installed with amsfonts and amsmath in order to evaluate them.
|
|
||||||
|
|
||||||
In summary, if you want to install Sphinx version 2.4.4, you should do::
|
In summary, if you want to install Sphinx version 2.4.4, you should do::
|
||||||
|
|
||||||
$ virtualenv sphinx_2.4.4
|
$ virtualenv sphinx_2.4.4
|
||||||
@ -86,6 +82,27 @@ Depending on the distribution, you may also need to install a series of
|
|||||||
``texlive`` packages that provide the minimal set of functionalities
|
``texlive`` packages that provide the minimal set of functionalities
|
||||||
required for ``XeLaTeX`` to work.
|
required for ``XeLaTeX`` to work.
|
||||||
|
|
||||||
|
Math Expressions in HTML
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Some ReST pages contain math expressions. Due to the way Sphinx works,
|
||||||
|
those expressions are written using LaTeX notation.
|
||||||
|
There are two options for Sphinx to render math expressions in html output.
|
||||||
|
One is an extension called `imgmath`_ which converts math expressions into
|
||||||
|
images and embeds them in html pages.
|
||||||
|
The other is an extension called `mathjax`_ which delegates math rendering
|
||||||
|
to JavaScript capable web browsers.
|
||||||
|
The former was the only option for pre-6.1 kernel documentation and it
|
||||||
|
requires quite a few texlive packages including amsfonts and amsmath among
|
||||||
|
others.
|
||||||
|
|
||||||
|
Since kernel release 6.1, html pages with math expressions can be built
|
||||||
|
without installing any texlive packages. See `Choice of Math Renderer`_ for
|
||||||
|
further info.
|
||||||
|
|
||||||
|
.. _imgmath: https://www.sphinx-doc.org/en/master/usage/extensions/math.html#module-sphinx.ext.imgmath
|
||||||
|
.. _mathjax: https://www.sphinx-doc.org/en/master/usage/extensions/math.html#module-sphinx.ext.mathjax
|
||||||
|
|
||||||
.. _sphinx-pre-install:
|
.. _sphinx-pre-install:
|
||||||
|
|
||||||
Checking for Sphinx dependencies
|
Checking for Sphinx dependencies
|
||||||
@ -164,6 +181,38 @@ To remove the generated documentation, run ``make cleandocs``.
|
|||||||
as well would improve the quality of images embedded in PDF
|
as well would improve the quality of images embedded in PDF
|
||||||
documents, especially for kernel releases 5.18 and later.
|
documents, especially for kernel releases 5.18 and later.
|
||||||
|
|
||||||
|
Choice of Math Renderer
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Since kernel release 6.1, mathjax works as a fallback math renderer for
|
||||||
|
html output.\ [#sph1_8]_
|
||||||
|
|
||||||
|
Math renderer is chosen depending on available commands as shown below:
|
||||||
|
|
||||||
|
.. table:: Math Renderer Choices for HTML
|
||||||
|
|
||||||
|
============= ================= ============
|
||||||
|
Math renderer Required commands Image format
|
||||||
|
============= ================= ============
|
||||||
|
imgmath latex, dvipng PNG (raster)
|
||||||
|
mathjax
|
||||||
|
============= ================= ============
|
||||||
|
|
||||||
|
The choice can be overridden by setting an environment variable
|
||||||
|
``SPHINX_IMGMATH`` as shown below:
|
||||||
|
|
||||||
|
.. table:: Effect of Setting ``SPHINX_IMGMATH``
|
||||||
|
|
||||||
|
====================== ========
|
||||||
|
Setting Renderer
|
||||||
|
====================== ========
|
||||||
|
``SPHINX_IMGMATH=yes`` imgmath
|
||||||
|
``SPHINX_IMGMATH=no`` mathjax
|
||||||
|
====================== ========
|
||||||
|
|
||||||
|
.. [#sph1_8] Fallback of math renderer requires Sphinx >=1.8.
|
||||||
|
|
||||||
|
|
||||||
Writing Documentation
|
Writing Documentation
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
@ -301,6 +301,7 @@ IO region
|
|||||||
devm_release_region()
|
devm_release_region()
|
||||||
devm_release_resource()
|
devm_release_resource()
|
||||||
devm_request_mem_region()
|
devm_request_mem_region()
|
||||||
|
devm_request_free_mem_region()
|
||||||
devm_request_region()
|
devm_request_region()
|
||||||
devm_request_resource()
|
devm_request_resource()
|
||||||
|
|
||||||
@ -334,7 +335,7 @@ IRQ
|
|||||||
devm_irq_alloc_descs_from()
|
devm_irq_alloc_descs_from()
|
||||||
devm_irq_alloc_generic_chip()
|
devm_irq_alloc_generic_chip()
|
||||||
devm_irq_setup_generic_chip()
|
devm_irq_setup_generic_chip()
|
||||||
devm_irq_sim_init()
|
devm_irq_domain_create_sim()
|
||||||
|
|
||||||
LED
|
LED
|
||||||
devm_led_classdev_register()
|
devm_led_classdev_register()
|
||||||
@ -392,7 +393,9 @@ PHY
|
|||||||
PINCTRL
|
PINCTRL
|
||||||
devm_pinctrl_get()
|
devm_pinctrl_get()
|
||||||
devm_pinctrl_put()
|
devm_pinctrl_put()
|
||||||
|
devm_pinctrl_get_select()
|
||||||
devm_pinctrl_register()
|
devm_pinctrl_register()
|
||||||
|
devm_pinctrl_register_and_init()
|
||||||
devm_pinctrl_unregister()
|
devm_pinctrl_unregister()
|
||||||
|
|
||||||
POWER
|
POWER
|
||||||
@ -427,6 +430,8 @@ SLAVE DMA ENGINE
|
|||||||
devm_acpi_dma_controller_register()
|
devm_acpi_dma_controller_register()
|
||||||
|
|
||||||
SPI
|
SPI
|
||||||
|
devm_spi_alloc_master()
|
||||||
|
devm_spi_alloc_slave()
|
||||||
devm_spi_register_master()
|
devm_spi_register_master()
|
||||||
|
|
||||||
WATCHDOG
|
WATCHDOG
|
||||||
|
@ -100,7 +100,7 @@ I believe platform_data is available for this, but if rather not, moving
|
|||||||
the isa_driver pointer to the private struct isa_dev is ofcourse fine as
|
the isa_driver pointer to the private struct isa_dev is ofcourse fine as
|
||||||
well.
|
well.
|
||||||
|
|
||||||
Then, if the the driver did not provide a .match, it matches. If it did,
|
Then, if the driver did not provide a .match, it matches. If it did,
|
||||||
the driver match() method is called to determine a match.
|
the driver match() method is called to determine a match.
|
||||||
|
|
||||||
If it did **not** match, dev->platform_data is reset to indicate this to
|
If it did **not** match, dev->platform_data is reset to indicate this to
|
||||||
|
@ -86,17 +86,24 @@ Module Options
|
|||||||
Special configuration for udlfb is usually unnecessary. There are a few
|
Special configuration for udlfb is usually unnecessary. There are a few
|
||||||
options, however.
|
options, however.
|
||||||
|
|
||||||
From the command line, pass options to modprobe
|
From the command line, pass options to modprobe::
|
||||||
modprobe udlfb fb_defio=0 console=1 shadow=1
|
|
||||||
|
|
||||||
Or modify options on the fly at /sys/module/udlfb/parameters directory via
|
modprobe udlfb fb_defio=0 console=1 shadow=1
|
||||||
sudo nano fb_defio
|
|
||||||
change the parameter in place, and save the file.
|
|
||||||
|
|
||||||
Unplug/replug USB device to apply with new settings
|
Or change options on the fly by editing
|
||||||
|
/sys/module/udlfb/parameters/PARAMETER_NAME ::
|
||||||
|
|
||||||
Or for permanent option, create file like /etc/modprobe.d/udlfb.conf with text
|
cd /sys/module/udlfb/parameters
|
||||||
options udlfb fb_defio=0 console=1 shadow=1
|
ls # to see a list of parameter names
|
||||||
|
sudo nano PARAMETER_NAME
|
||||||
|
# change the parameter in place, and save the file.
|
||||||
|
|
||||||
|
Unplug/replug USB device to apply with new settings.
|
||||||
|
|
||||||
|
Or to apply options permanently, create a modprobe configuration file
|
||||||
|
like /etc/modprobe.d/udlfb.conf with text::
|
||||||
|
|
||||||
|
options udlfb fb_defio=0 console=1 shadow=1
|
||||||
|
|
||||||
Accepted boolean options:
|
Accepted boolean options:
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ volumes, calling::
|
|||||||
to tell fscache that a volume has been withdrawn. This waits for all
|
to tell fscache that a volume has been withdrawn. This waits for all
|
||||||
outstanding accesses on the volume to complete before returning.
|
outstanding accesses on the volume to complete before returning.
|
||||||
|
|
||||||
When the the cache is completely withdrawn, fscache should be notified by
|
When the cache is completely withdrawn, fscache should be notified by
|
||||||
calling::
|
calling::
|
||||||
|
|
||||||
void fscache_relinquish_cache(struct fscache_cache *cache);
|
void fscache_relinquish_cache(struct fscache_cache *cache);
|
||||||
|
@ -456,15 +456,15 @@ The ext4 superblock is laid out as follows in
|
|||||||
* - 0x277
|
* - 0x277
|
||||||
- __u8
|
- __u8
|
||||||
- s_lastcheck_hi
|
- s_lastcheck_hi
|
||||||
- Upper 8 bits of the s_lastcheck_hi field.
|
- Upper 8 bits of the s_lastcheck field.
|
||||||
* - 0x278
|
* - 0x278
|
||||||
- __u8
|
- __u8
|
||||||
- s_first_error_time_hi
|
- s_first_error_time_hi
|
||||||
- Upper 8 bits of the s_first_error_time_hi field.
|
- Upper 8 bits of the s_first_error_time field.
|
||||||
* - 0x279
|
* - 0x279
|
||||||
- __u8
|
- __u8
|
||||||
- s_last_error_time_hi
|
- s_last_error_time_hi
|
||||||
- Upper 8 bits of the s_last_error_time_hi field.
|
- Upper 8 bits of the s_last_error_time field.
|
||||||
* - 0x27A
|
* - 0x27A
|
||||||
- __u8
|
- __u8
|
||||||
- s_pad[2]
|
- s_pad[2]
|
||||||
|
@ -286,9 +286,8 @@ compress_algorithm=%s:%d Control compress algorithm and its compress level, now,
|
|||||||
algorithm level range
|
algorithm level range
|
||||||
lz4 3 - 16
|
lz4 3 - 16
|
||||||
zstd 1 - 22
|
zstd 1 - 22
|
||||||
compress_log_size=%u Support configuring compress cluster size, the size will
|
compress_log_size=%u Support configuring compress cluster size. The size will
|
||||||
be 4KB * (1 << %u), 16KB is minimum size, also it's
|
be 4KB * (1 << %u). The default and minimum sizes are 16KB.
|
||||||
default size.
|
|
||||||
compress_extension=%s Support adding specified extension, so that f2fs can enable
|
compress_extension=%s Support adding specified extension, so that f2fs can enable
|
||||||
compression on those corresponding files, e.g. if all files
|
compression on those corresponding files, e.g. if all files
|
||||||
with '.ext' has high compression rate, we can set the '.ext'
|
with '.ext' has high compression rate, we can set the '.ext'
|
||||||
|
@ -661,7 +661,7 @@ idmappings::
|
|||||||
mount idmapping: u0:k10000:r10000
|
mount idmapping: u0:k10000:r10000
|
||||||
|
|
||||||
Assume a file owned by ``u1000`` is read from disk. The filesystem maps this id
|
Assume a file owned by ``u1000`` is read from disk. The filesystem maps this id
|
||||||
to ``k21000`` according to it's idmapping. This is what is stored in the
|
to ``k21000`` according to its idmapping. This is what is stored in the
|
||||||
inode's ``i_uid`` and ``i_gid`` fields.
|
inode's ``i_uid`` and ``i_gid`` fields.
|
||||||
|
|
||||||
When the caller queries the ownership of this file via ``stat()`` the kernel
|
When the caller queries the ownership of this file via ``stat()`` the kernel
|
||||||
|
@ -176,7 +176,7 @@ Then userspace.
|
|||||||
The requirement for a static, fixed preallocated system area comes from how
|
The requirement for a static, fixed preallocated system area comes from how
|
||||||
qnx6fs deals with writes.
|
qnx6fs deals with writes.
|
||||||
|
|
||||||
Each superblock got it's own half of the system area. So superblock #1
|
Each superblock got its own half of the system area. So superblock #1
|
||||||
always uses blocks from the lower half while superblock #2 just writes to
|
always uses blocks from the lower half while superblock #2 just writes to
|
||||||
blocks represented by the upper half bitmap system area bits.
|
blocks represented by the upper half bitmap system area bits.
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ Files
|
|||||||
from the data buffer, updating the value of the specified signal
|
from the data buffer, updating the value of the specified signal
|
||||||
notification register. The signal notification register will
|
notification register. The signal notification register will
|
||||||
either be replaced with the input data or will be updated to the
|
either be replaced with the input data or will be updated to the
|
||||||
bitwise OR or the old value and the input data, depending on the
|
bitwise OR of the old value and the input data, depending on the
|
||||||
contents of the signal1_type, or signal2_type respectively,
|
contents of the signal1_type, or signal2_type respectively,
|
||||||
file.
|
file.
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ transactions together::
|
|||||||
|
|
||||||
ntp = xfs_trans_dup(tp);
|
ntp = xfs_trans_dup(tp);
|
||||||
xfs_trans_commit(tp);
|
xfs_trans_commit(tp);
|
||||||
xfs_log_reserve(ntp);
|
xfs_trans_reserve(ntp);
|
||||||
|
|
||||||
This results in a series of "rolling transactions" where the inode is locked
|
This results in a series of "rolling transactions" where the inode is locked
|
||||||
across the entire chain of transactions. Hence while this series of rolling
|
across the entire chain of transactions. Hence while this series of rolling
|
||||||
@ -191,7 +191,7 @@ transaction rolling mechanism to re-reserve space on every transaction roll. We
|
|||||||
know from the implementation of the permanent transactions how many transaction
|
know from the implementation of the permanent transactions how many transaction
|
||||||
rolls are likely for the common modifications that need to be made.
|
rolls are likely for the common modifications that need to be made.
|
||||||
|
|
||||||
For example, and inode allocation is typically two transactions - one to
|
For example, an inode allocation is typically two transactions - one to
|
||||||
physically allocate a free inode chunk on disk, and another to allocate an inode
|
physically allocate a free inode chunk on disk, and another to allocate an inode
|
||||||
from an inode chunk that has free inodes in it. Hence for an inode allocation
|
from an inode chunk that has free inodes in it. Hence for an inode allocation
|
||||||
transaction, we might set the reservation log count to a value of 2 to indicate
|
transaction, we might set the reservation log count to a value of 2 to indicate
|
||||||
@ -200,7 +200,7 @@ chain. Each time a permanent transaction rolls, it consumes an entire unit
|
|||||||
reservation.
|
reservation.
|
||||||
|
|
||||||
Hence when the permanent transaction is first allocated, the log space
|
Hence when the permanent transaction is first allocated, the log space
|
||||||
reservation is increases from a single unit reservation to multiple unit
|
reservation is increased from a single unit reservation to multiple unit
|
||||||
reservations. That multiple is defined by the reservation log count, and this
|
reservations. That multiple is defined by the reservation log count, and this
|
||||||
means we can roll the transaction multiple times before we have to re-reserve
|
means we can roll the transaction multiple times before we have to re-reserve
|
||||||
log space when we roll the transaction. This ensures that the common
|
log space when we roll the transaction. This ensures that the common
|
||||||
@ -259,7 +259,7 @@ the next transaction in the sequeunce, but we have none remaining. We cannot
|
|||||||
sleep during the transaction commit process waiting for new log space to become
|
sleep during the transaction commit process waiting for new log space to become
|
||||||
available, as we may end up on the end of the FIFO queue and the items we have
|
available, as we may end up on the end of the FIFO queue and the items we have
|
||||||
locked while we sleep could end up pinning the tail of the log before there is
|
locked while we sleep could end up pinning the tail of the log before there is
|
||||||
enough free space in the log to fulfil all of the pending reservations and
|
enough free space in the log to fulfill all of the pending reservations and
|
||||||
then wake up transaction commit in progress.
|
then wake up transaction commit in progress.
|
||||||
|
|
||||||
To take a new reservation without sleeping requires us to be able to take a
|
To take a new reservation without sleeping requires us to be able to take a
|
||||||
@ -551,14 +551,14 @@ Essentially, this shows that an item that is in the AIL can still be modified
|
|||||||
and relogged, so any tracking must be separate to the AIL infrastructure. As
|
and relogged, so any tracking must be separate to the AIL infrastructure. As
|
||||||
such, we cannot reuse the AIL list pointers for tracking committed items, nor
|
such, we cannot reuse the AIL list pointers for tracking committed items, nor
|
||||||
can we store state in any field that is protected by the AIL lock. Hence the
|
can we store state in any field that is protected by the AIL lock. Hence the
|
||||||
committed item tracking needs it's own locks, lists and state fields in the log
|
committed item tracking needs its own locks, lists and state fields in the log
|
||||||
item.
|
item.
|
||||||
|
|
||||||
Similar to the AIL, tracking of committed items is done through a new list
|
Similar to the AIL, tracking of committed items is done through a new list
|
||||||
called the Committed Item List (CIL). The list tracks log items that have been
|
called the Committed Item List (CIL). The list tracks log items that have been
|
||||||
committed and have formatted memory buffers attached to them. It tracks objects
|
committed and have formatted memory buffers attached to them. It tracks objects
|
||||||
in transaction commit order, so when an object is relogged it is removed from
|
in transaction commit order, so when an object is relogged it is removed from
|
||||||
it's place in the list and re-inserted at the tail. This is entirely arbitrary
|
its place in the list and re-inserted at the tail. This is entirely arbitrary
|
||||||
and done to make it easy for debugging - the last items in the list are the
|
and done to make it easy for debugging - the last items in the list are the
|
||||||
ones that are most recently modified. Ordering of the CIL is not necessary for
|
ones that are most recently modified. Ordering of the CIL is not necessary for
|
||||||
transactional integrity (as discussed in the next section) so the ordering is
|
transactional integrity (as discussed in the next section) so the ordering is
|
||||||
@ -615,7 +615,7 @@ those changes into the current checkpoint context. We then initialise a new
|
|||||||
context and attach that to the CIL for aggregation of new transactions.
|
context and attach that to the CIL for aggregation of new transactions.
|
||||||
|
|
||||||
This allows us to unlock the CIL immediately after transfer of all the
|
This allows us to unlock the CIL immediately after transfer of all the
|
||||||
committed items and effectively allow new transactions to be issued while we
|
committed items and effectively allows new transactions to be issued while we
|
||||||
are formatting the checkpoint into the log. It also allows concurrent
|
are formatting the checkpoint into the log. It also allows concurrent
|
||||||
checkpoints to be written into the log buffers in the case of log force heavy
|
checkpoints to be written into the log buffers in the case of log force heavy
|
||||||
workloads, just like the existing transaction commit code does. This, however,
|
workloads, just like the existing transaction commit code does. This, however,
|
||||||
@ -884,9 +884,9 @@ pin the object the first time it is inserted into the CIL - if it is already in
|
|||||||
the CIL during a transaction commit, then we do not pin it again. Because there
|
the CIL during a transaction commit, then we do not pin it again. Because there
|
||||||
can be multiple outstanding checkpoint contexts, we can still see elevated pin
|
can be multiple outstanding checkpoint contexts, we can still see elevated pin
|
||||||
counts, but as each checkpoint completes the pin count will retain the correct
|
counts, but as each checkpoint completes the pin count will retain the correct
|
||||||
value according to it's context.
|
value according to its context.
|
||||||
|
|
||||||
Just to make matters more slightly more complex, this checkpoint level context
|
Just to make matters slightly more complex, this checkpoint level context
|
||||||
for the pin count means that the pinning of an item must take place under the
|
for the pin count means that the pinning of an item must take place under the
|
||||||
CIL commit/flush lock. If we pin the object outside this lock, we cannot
|
CIL commit/flush lock. If we pin the object outside this lock, we cannot
|
||||||
guarantee which context the pin count is associated with. This is because of
|
guarantee which context the pin count is associated with. This is because of
|
||||||
|
@ -1,11 +1,5 @@
|
|||||||
.. SPDX-License-Identifier: GPL-2.0
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
|
||||||
.. The Linux Kernel documentation master file, created by
|
|
||||||
sphinx-quickstart on Fri Feb 12 13:51:46 2016.
|
|
||||||
You can adapt this file completely to your liking, but it should at least
|
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
.. _linux_doc:
|
.. _linux_doc:
|
||||||
|
|
||||||
The Linux Kernel documentation
|
The Linux Kernel documentation
|
||||||
@ -18,26 +12,72 @@ documents into a coherent whole. Please note that improvements to the
|
|||||||
documentation are welcome; join the linux-doc list at vger.kernel.org if
|
documentation are welcome; join the linux-doc list at vger.kernel.org if
|
||||||
you want to help out.
|
you want to help out.
|
||||||
|
|
||||||
Licensing documentation
|
Working with the development community
|
||||||
-----------------------
|
--------------------------------------
|
||||||
|
|
||||||
The following describes the license of the Linux kernel source code
|
The essential guides for interacting with the kernel's development
|
||||||
(GPLv2), how to properly mark the license of individual files in the source
|
community and getting your work upstream.
|
||||||
tree, as well as links to the full license text.
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
process/development-process
|
||||||
|
process/submitting-patches
|
||||||
|
Code of conduct <process/code-of-conduct>
|
||||||
|
maintainer/index
|
||||||
|
All development-process docs <process/index>
|
||||||
|
|
||||||
|
|
||||||
|
Internal API manuals
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Manuals for use by developers working to interface with the rest of the
|
||||||
|
kernel.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
core-api/index
|
||||||
|
driver-api/index
|
||||||
|
subsystem-apis
|
||||||
|
Locking in the kernel <locking/index>
|
||||||
|
|
||||||
|
Development tools and processes
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Various other manuals with useful information for all kernel developers.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
process/license-rules
|
||||||
|
doc-guide/index
|
||||||
|
dev-tools/index
|
||||||
|
dev-tools/testing-overview
|
||||||
|
kernel-hacking/index
|
||||||
|
trace/index
|
||||||
|
fault-injection/index
|
||||||
|
livepatch/index
|
||||||
|
|
||||||
* :ref:`kernel_licensing`
|
|
||||||
|
|
||||||
User-oriented documentation
|
User-oriented documentation
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
The following manuals are written for *users* of the kernel — those who are
|
The following manuals are written for *users* of the kernel — those who are
|
||||||
trying to get it to work optimally on a given system.
|
trying to get it to work optimally on a given system and application
|
||||||
|
developers seeking information on the kernel's user-space APIs.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 1
|
||||||
|
|
||||||
admin-guide/index
|
admin-guide/index
|
||||||
kbuild/index
|
The kernel build system <kbuild/index>
|
||||||
|
admin-guide/reporting-issues.rst
|
||||||
|
User-space tools <tools/index>
|
||||||
|
userspace-api/index
|
||||||
|
|
||||||
|
See also: the `Linux man pages <https://www.kernel.org/doc/man-pages/>`_,
|
||||||
|
which are kept separately from the kernel's own documentation.
|
||||||
|
|
||||||
Firmware-related documentation
|
Firmware-related documentation
|
||||||
------------------------------
|
------------------------------
|
||||||
@ -45,106 +85,11 @@ The following holds information on the kernel's expectations regarding the
|
|||||||
platform firmwares.
|
platform firmwares.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 1
|
||||||
|
|
||||||
firmware-guide/index
|
firmware-guide/index
|
||||||
devicetree/index
|
devicetree/index
|
||||||
|
|
||||||
Application-developer documentation
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
The user-space API manual gathers together documents describing aspects of
|
|
||||||
the kernel interface as seen by application developers.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
userspace-api/index
|
|
||||||
|
|
||||||
|
|
||||||
Introduction to kernel development
|
|
||||||
----------------------------------
|
|
||||||
|
|
||||||
These manuals contain overall information about how to develop the kernel.
|
|
||||||
The kernel community is quite large, with thousands of developers
|
|
||||||
contributing over the course of a year. As with any large community,
|
|
||||||
knowing how things are done will make the process of getting your changes
|
|
||||||
merged much easier.
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
process/index
|
|
||||||
dev-tools/index
|
|
||||||
doc-guide/index
|
|
||||||
kernel-hacking/index
|
|
||||||
trace/index
|
|
||||||
maintainer/index
|
|
||||||
fault-injection/index
|
|
||||||
livepatch/index
|
|
||||||
|
|
||||||
|
|
||||||
Kernel API documentation
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
These books get into the details of how specific kernel subsystems work
|
|
||||||
from the point of view of a kernel developer. Much of the information here
|
|
||||||
is taken directly from the kernel source, with supplemental material added
|
|
||||||
as needed (or at least as we managed to add it — probably *not* all that is
|
|
||||||
needed).
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
driver-api/index
|
|
||||||
core-api/index
|
|
||||||
locking/index
|
|
||||||
accounting/index
|
|
||||||
block/index
|
|
||||||
cdrom/index
|
|
||||||
cpu-freq/index
|
|
||||||
fb/index
|
|
||||||
fpga/index
|
|
||||||
hid/index
|
|
||||||
i2c/index
|
|
||||||
iio/index
|
|
||||||
isdn/index
|
|
||||||
infiniband/index
|
|
||||||
leds/index
|
|
||||||
netlabel/index
|
|
||||||
networking/index
|
|
||||||
pcmcia/index
|
|
||||||
power/index
|
|
||||||
target/index
|
|
||||||
timers/index
|
|
||||||
spi/index
|
|
||||||
w1/index
|
|
||||||
watchdog/index
|
|
||||||
virt/index
|
|
||||||
input/index
|
|
||||||
hwmon/index
|
|
||||||
gpu/index
|
|
||||||
security/index
|
|
||||||
sound/index
|
|
||||||
crypto/index
|
|
||||||
filesystems/index
|
|
||||||
mm/index
|
|
||||||
bpf/index
|
|
||||||
usb/index
|
|
||||||
PCI/index
|
|
||||||
scsi/index
|
|
||||||
misc-devices/index
|
|
||||||
scheduler/index
|
|
||||||
mhi/index
|
|
||||||
peci/index
|
|
||||||
|
|
||||||
Architecture-agnostic documentation
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 2
|
|
||||||
|
|
||||||
asm-annotations
|
|
||||||
|
|
||||||
Architecture-specific documentation
|
Architecture-specific documentation
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
@ -163,9 +108,8 @@ of the documentation body, or may require some adjustments and/or conversion
|
|||||||
to ReStructured Text format, or are simply too old.
|
to ReStructured Text format, or are simply too old.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 1
|
||||||
|
|
||||||
tools/index
|
|
||||||
staging/index
|
staging/index
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,7 +90,11 @@ e.g., on Ubuntu for gcc-10::
|
|||||||
|
|
||||||
Or on Fedora::
|
Or on Fedora::
|
||||||
|
|
||||||
dnf install gcc-plugin-devel
|
dnf install gcc-plugin-devel libmpc-devel
|
||||||
|
|
||||||
|
Or on Fedora when using cross-compilers that include plugins::
|
||||||
|
|
||||||
|
dnf install libmpc-devel
|
||||||
|
|
||||||
Enable the GCC plugin infrastructure and some plugin(s) you want to use
|
Enable the GCC plugin infrastructure and some plugin(s) you want to use
|
||||||
in the kernel config::
|
in the kernel config::
|
||||||
@ -99,6 +103,19 @@ in the kernel config::
|
|||||||
CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y
|
CONFIG_GCC_PLUGIN_LATENT_ENTROPY=y
|
||||||
...
|
...
|
||||||
|
|
||||||
|
Run gcc (native or cross-compiler) to ensure plugin headers are detected::
|
||||||
|
|
||||||
|
gcc -print-file-name=plugin
|
||||||
|
CROSS_COMPILE=arm-linux-gnu- ${CROSS_COMPILE}gcc -print-file-name=plugin
|
||||||
|
|
||||||
|
The word "plugin" means they are not detected::
|
||||||
|
|
||||||
|
plugin
|
||||||
|
|
||||||
|
A full path means they are detected::
|
||||||
|
|
||||||
|
/usr/lib/gcc/x86_64-redhat-linux/12/plugin
|
||||||
|
|
||||||
To compile the minimum tool set including the plugin(s)::
|
To compile the minimum tool set including the plugin(s)::
|
||||||
|
|
||||||
make scripts
|
make scripts
|
||||||
|
@ -39,7 +39,7 @@ as the writer can invalidate a pointer that the reader is following.
|
|||||||
Sequence counters (``seqcount_t``)
|
Sequence counters (``seqcount_t``)
|
||||||
==================================
|
==================================
|
||||||
|
|
||||||
This is the the raw counting mechanism, which does not protect against
|
This is the raw counting mechanism, which does not protect against
|
||||||
multiple writers. Write side critical sections must thus be serialized
|
multiple writers. Write side critical sections must thus be serialized
|
||||||
by an external lock.
|
by an external lock.
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ unevictable list for the memory cgroup and node being scanned.
|
|||||||
There may be situations where a page is mapped into a VM_LOCKED VMA, but the
|
There may be situations where a page is mapped into a VM_LOCKED VMA, but the
|
||||||
page is not marked as PG_mlocked. Such pages will make it all the way to
|
page is not marked as PG_mlocked. Such pages will make it all the way to
|
||||||
shrink_active_list() or shrink_page_list() where they will be detected when
|
shrink_active_list() or shrink_page_list() where they will be detected when
|
||||||
vmscan walks the reverse map in page_referenced() or try_to_unmap(). The page
|
vmscan walks the reverse map in folio_referenced() or try_to_unmap(). The page
|
||||||
is culled to the unevictable list when it is released by the shrinker.
|
is culled to the unevictable list when it is released by the shrinker.
|
||||||
|
|
||||||
To "cull" an unevictable page, vmscan simply puts the page back on the LRU list
|
To "cull" an unevictable page, vmscan simply puts the page back on the LRU list
|
||||||
@ -267,7 +267,7 @@ the LRU. Such pages can be "noticed" by memory management in several places:
|
|||||||
(4) in the fault path and when a VM_LOCKED stack segment is expanded; or
|
(4) in the fault path and when a VM_LOCKED stack segment is expanded; or
|
||||||
|
|
||||||
(5) as mentioned above, in vmscan:shrink_page_list() when attempting to
|
(5) as mentioned above, in vmscan:shrink_page_list() when attempting to
|
||||||
reclaim a page in a VM_LOCKED VMA by page_referenced() or try_to_unmap().
|
reclaim a page in a VM_LOCKED VMA by folio_referenced() or try_to_unmap().
|
||||||
|
|
||||||
mlocked pages become unlocked and rescued from the unevictable list when:
|
mlocked pages become unlocked and rescued from the unevictable list when:
|
||||||
|
|
||||||
@ -547,7 +547,7 @@ vmscan's shrink_inactive_list() and shrink_page_list() also divert obviously
|
|||||||
unevictable pages found on the inactive lists to the appropriate memory cgroup
|
unevictable pages found on the inactive lists to the appropriate memory cgroup
|
||||||
and node unevictable list.
|
and node unevictable list.
|
||||||
|
|
||||||
rmap's page_referenced_one(), called via vmscan's shrink_active_list() or
|
rmap's folio_referenced_one(), called via vmscan's shrink_active_list() or
|
||||||
shrink_page_list(), and rmap's try_to_unmap_one() called via shrink_page_list(),
|
shrink_page_list(), and rmap's try_to_unmap_one() called via shrink_page_list(),
|
||||||
check for (3) pages still mapped into VM_LOCKED VMAs, and call mlock_vma_page()
|
check for (3) pages still mapped into VM_LOCKED VMAs, and call mlock_vma_page()
|
||||||
to correct them. Such pages are culled to the unevictable list when released
|
to correct them. Such pages are culled to the unevictable list when released
|
||||||
|
@ -256,8 +256,10 @@ The tags in common use are:
|
|||||||
- Cc: the named person received a copy of the patch and had the
|
- Cc: the named person received a copy of the patch and had the
|
||||||
opportunity to comment on it.
|
opportunity to comment on it.
|
||||||
|
|
||||||
Be careful in the addition of tags to your patches: only Cc: is appropriate
|
Be careful in the addition of tags to your patches, as only Cc: is appropriate
|
||||||
for addition without the explicit permission of the person named.
|
for addition without the explicit permission of the person named; using
|
||||||
|
Reported-by: is fine most of the time as well, but ask for permission if
|
||||||
|
the bug was reported in private.
|
||||||
|
|
||||||
|
|
||||||
Sending the patch
|
Sending the patch
|
||||||
|
@ -51,7 +51,7 @@ the Technical Advisory Board (TAB) or other maintainers if you're
|
|||||||
uncertain how to handle situations that come up. It will not be
|
uncertain how to handle situations that come up. It will not be
|
||||||
considered a violation report unless you want it to be. If you are
|
considered a violation report unless you want it to be. If you are
|
||||||
uncertain about approaching the TAB or any other maintainers, please
|
uncertain about approaching the TAB or any other maintainers, please
|
||||||
reach out to our conflict mediator, Mishi Choudhary <mishi@linux.com>.
|
reach out to our conflict mediator, Joanna Lee <joanna.lee@gesmer.com>.
|
||||||
|
|
||||||
In the end, "be kind to each other" is really what the end goal is for
|
In the end, "be kind to each other" is really what the end goal is for
|
||||||
everybody. We know everyone is human and we all fail at times, but the
|
everybody. We know everyone is human and we all fail at times, but the
|
||||||
@ -127,10 +127,12 @@ are listed at https://kernel.org/code-of-conduct.html. Members can not
|
|||||||
access reports made before they joined or after they have left the
|
access reports made before they joined or after they have left the
|
||||||
committee.
|
committee.
|
||||||
|
|
||||||
The initial Code of Conduct Committee consists of volunteer members of
|
The Code of Conduct Committee consists of volunteer community members
|
||||||
the TAB, as well as a professional mediator acting as a neutral third
|
appointed by the TAB, as well as a professional mediator acting as a
|
||||||
party. The first task of the committee is to establish documented
|
neutral third party. The processes the Code of Conduct committee will
|
||||||
processes, which will be made public.
|
use to address reports is varied and will depend on the individual
|
||||||
|
circumstance, however, this file serves as documentation for the
|
||||||
|
general process used.
|
||||||
|
|
||||||
Any member of the committee, including the mediator, can be contacted
|
Any member of the committee, including the mediator, can be contacted
|
||||||
directly if a reporter does not wish to include the full committee in a
|
directly if a reporter does not wish to include the full committee in a
|
||||||
@ -141,16 +143,16 @@ processes (see above) and consults with the TAB as needed and
|
|||||||
appropriate, for instance to request and receive information about the
|
appropriate, for instance to request and receive information about the
|
||||||
kernel community.
|
kernel community.
|
||||||
|
|
||||||
Any decisions by the committee will be brought to the TAB, for
|
Any decisions regarding enforcement recommendations will be brought to
|
||||||
implementation of enforcement with the relevant maintainers if needed.
|
the TAB for implementation of enforcement with the relevant maintainers
|
||||||
A decision by the Code of Conduct Committee can be overturned by the TAB
|
if needed. A decision by the Code of Conduct Committee can be overturned
|
||||||
by a two-thirds vote.
|
by the TAB by a two-thirds vote.
|
||||||
|
|
||||||
At quarterly intervals, the Code of Conduct Committee and TAB will
|
At quarterly intervals, the Code of Conduct Committee and TAB will
|
||||||
provide a report summarizing the anonymised reports that the Code of
|
provide a report summarizing the anonymised reports that the Code of
|
||||||
Conduct committee has received and their status, as well details of any
|
Conduct committee has received and their status, as well details of any
|
||||||
overridden decisions including complete and identifiable voting details.
|
overridden decisions including complete and identifiable voting details.
|
||||||
|
|
||||||
We expect to establish a different process for Code of Conduct Committee
|
Because how we interpret and enforce the Code of Conduct will evolve over
|
||||||
staffing beyond the bootstrap period. This document will be updated
|
time, this document will be updated when necessary to reflect any
|
||||||
with that information when this occurs.
|
changes.
|
||||||
|
@ -1186,6 +1186,68 @@ expression used. For instance:
|
|||||||
#endif /* CONFIG_SOMETHING */
|
#endif /* CONFIG_SOMETHING */
|
||||||
|
|
||||||
|
|
||||||
|
22) Do not crash the kernel
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
In general, the decision to crash the kernel belongs to the user, rather
|
||||||
|
than to the kernel developer.
|
||||||
|
|
||||||
|
Avoid panic()
|
||||||
|
*************
|
||||||
|
|
||||||
|
panic() should be used with care and primarily only during system boot.
|
||||||
|
panic() is, for example, acceptable when running out of memory during boot and
|
||||||
|
not being able to continue.
|
||||||
|
|
||||||
|
Use WARN() rather than BUG()
|
||||||
|
****************************
|
||||||
|
|
||||||
|
Do not add new code that uses any of the BUG() variants, such as BUG(),
|
||||||
|
BUG_ON(), or VM_BUG_ON(). Instead, use a WARN*() variant, preferably
|
||||||
|
WARN_ON_ONCE(), and possibly with recovery code. Recovery code is not
|
||||||
|
required if there is no reasonable way to at least partially recover.
|
||||||
|
|
||||||
|
"I'm too lazy to do error handling" is not an excuse for using BUG(). Major
|
||||||
|
internal corruptions with no way of continuing may still use BUG(), but need
|
||||||
|
good justification.
|
||||||
|
|
||||||
|
Use WARN_ON_ONCE() rather than WARN() or WARN_ON()
|
||||||
|
**************************************************
|
||||||
|
|
||||||
|
WARN_ON_ONCE() is generally preferred over WARN() or WARN_ON(), because it
|
||||||
|
is common for a given warning condition, if it occurs at all, to occur
|
||||||
|
multiple times. This can fill up and wrap the kernel log, and can even slow
|
||||||
|
the system enough that the excessive logging turns into its own, additional
|
||||||
|
problem.
|
||||||
|
|
||||||
|
Do not WARN lightly
|
||||||
|
*******************
|
||||||
|
|
||||||
|
WARN*() is intended for unexpected, this-should-never-happen situations.
|
||||||
|
WARN*() macros are not to be used for anything that is expected to happen
|
||||||
|
during normal operation. These are not pre- or post-condition asserts, for
|
||||||
|
example. Again: WARN*() must not be used for a condition that is expected
|
||||||
|
to trigger easily, for example, by user space actions. pr_warn_once() is a
|
||||||
|
possible alternative, if you need to notify the user of a problem.
|
||||||
|
|
||||||
|
Do not worry about panic_on_warn users
|
||||||
|
**************************************
|
||||||
|
|
||||||
|
A few more words about panic_on_warn: Remember that ``panic_on_warn`` is an
|
||||||
|
available kernel option, and that many users set this option. This is why
|
||||||
|
there is a "Do not WARN lightly" writeup, above. However, the existence of
|
||||||
|
panic_on_warn users is not a valid reason to avoid the judicious use
|
||||||
|
WARN*(). That is because, whoever enables panic_on_warn has explicitly
|
||||||
|
asked the kernel to crash if a WARN*() fires, and such users must be
|
||||||
|
prepared to deal with the consequences of a system that is somewhat more
|
||||||
|
likely to crash.
|
||||||
|
|
||||||
|
Use BUILD_BUG_ON() for compile-time assertions
|
||||||
|
**********************************************
|
||||||
|
|
||||||
|
The use of BUILD_BUG_ON() is acceptable and encouraged, because it is a
|
||||||
|
compile-time assertion that has no effect at runtime.
|
||||||
|
|
||||||
Appendix I) References
|
Appendix I) References
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
.. _process_index:
|
.. _process_index:
|
||||||
|
|
||||||
|
=============================================
|
||||||
Working with the kernel development community
|
Working with the kernel development community
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
|
@ -121,57 +121,56 @@ edit your ``~/.gnupg/gpg-agent.conf`` file to set your own values::
|
|||||||
to remove anything you had in place for older versions of GnuPG, as
|
to remove anything you had in place for older versions of GnuPG, as
|
||||||
it may not be doing the right thing any more.
|
it may not be doing the right thing any more.
|
||||||
|
|
||||||
Set up a refresh cronjob
|
.. _protect_your_key:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
You will need to regularly refresh your keyring in order to get the
|
Protect your PGP key
|
||||||
latest changes on other people's public keys, which is best done with a
|
====================
|
||||||
daily cronjob::
|
|
||||||
|
|
||||||
@daily /usr/bin/gpg2 --refresh >/dev/null 2>&1
|
|
||||||
|
|
||||||
Check the full path to your ``gpg`` or ``gpg2`` command and use the
|
|
||||||
``gpg2`` command if regular ``gpg`` for you is the legacy GnuPG v.1.
|
|
||||||
|
|
||||||
.. _master_key:
|
|
||||||
|
|
||||||
Protect your master PGP key
|
|
||||||
===========================
|
|
||||||
|
|
||||||
This guide assumes that you already have a PGP key that you use for Linux
|
This guide assumes that you already have a PGP key that you use for Linux
|
||||||
kernel development purposes. If you do not yet have one, please see the
|
kernel development purposes. If you do not yet have one, please see the
|
||||||
"`Protecting Code Integrity`_" document mentioned earlier for guidance
|
"`Protecting Code Integrity`_" document mentioned earlier for guidance
|
||||||
on how to create a new one.
|
on how to create a new one.
|
||||||
|
|
||||||
You should also make a new key if your current one is weaker than 2048 bits
|
You should also make a new key if your current one is weaker than 2048
|
||||||
(RSA).
|
bits (RSA).
|
||||||
|
|
||||||
Master key vs. Subkeys
|
Understanding PGP Subkeys
|
||||||
----------------------
|
-------------------------
|
||||||
|
|
||||||
Subkeys are fully independent PGP keypairs that are tied to the "master"
|
A PGP key rarely consists of a single keypair -- usually it is a
|
||||||
key using certifying key signatures (certificates). It is important to
|
collection of independent subkeys that can be used for different
|
||||||
understand the following:
|
purposes based on their capabilities, assigned at their creation time.
|
||||||
|
PGP defines four capabilities that a key can have:
|
||||||
|
|
||||||
1. There are no technical differences between the "master key" and "subkeys."
|
- **[S]** keys can be used for signing
|
||||||
2. At creation time, we assign functional limitations to each key by
|
- **[E]** keys can be used for encryption
|
||||||
giving it specific capabilities.
|
- **[A]** keys can be used for authentication
|
||||||
3. A PGP key can have 4 capabilities:
|
- **[C]** keys can be used for certifying other keys
|
||||||
|
|
||||||
- **[S]** key can be used for signing
|
The key with the **[C]** capability is often called the "master" key,
|
||||||
- **[E]** key can be used for encryption
|
but this terminology is misleading because it implies that the Certify
|
||||||
- **[A]** key can be used for authentication
|
key can be used in place of any of other subkey on the same chain (like
|
||||||
- **[C]** key can be used for certifying other keys
|
a physical "master key" can be used to open the locks made for other
|
||||||
|
keys). Since this is not the case, this guide will refer to it as "the
|
||||||
|
Certify key" to avoid any ambiguity.
|
||||||
|
|
||||||
4. A single key may have multiple capabilities.
|
It is critical to fully understand the following:
|
||||||
5. A subkey is fully independent from the master key. A message
|
|
||||||
encrypted to a subkey cannot be decrypted with the master key. If you
|
|
||||||
lose your private subkey, it cannot be recreated from the master key
|
|
||||||
in any way.
|
|
||||||
|
|
||||||
The key carrying the **[C]** (certify) capability is considered the
|
1. All subkeys are fully independent from each other. If you lose a
|
||||||
"master" key because it is the only key that can be used to indicate
|
private subkey, it cannot be restored or recreated from any other
|
||||||
relationship with other keys. Only the **[C]** key can be used to:
|
private key on your chain.
|
||||||
|
2. With the exception of the Certify key, there can be multiple subkeys
|
||||||
|
with identical capabilities (e.g. you can have 2 valid encryption
|
||||||
|
subkeys, 3 valid signing subkeys, but only one valid certification
|
||||||
|
subkey). All subkeys are fully independent -- a message encrypted to
|
||||||
|
one **[E]** subkey cannot be decrypted with any other **[E]** subkey
|
||||||
|
you may also have.
|
||||||
|
3. A single subkey may have multiple capabilities (e.g. your **[C]** key
|
||||||
|
can also be your **[S]** key).
|
||||||
|
|
||||||
|
The key carrying the **[C]** (certify) capability is the only key that
|
||||||
|
can be used to indicate relationship with other keys. Only the **[C]**
|
||||||
|
key can be used to:
|
||||||
|
|
||||||
- add or revoke other keys (subkeys) with S/E/A capabilities
|
- add or revoke other keys (subkeys) with S/E/A capabilities
|
||||||
- add, change or revoke identities (uids) associated with the key
|
- add, change or revoke identities (uids) associated with the key
|
||||||
@ -180,7 +179,7 @@ relationship with other keys. Only the **[C]** key can be used to:
|
|||||||
|
|
||||||
By default, GnuPG creates the following when generating new keys:
|
By default, GnuPG creates the following when generating new keys:
|
||||||
|
|
||||||
- A master key carrying both Certify and Sign capabilities (**[SC]**)
|
- One subkey carrying both Certify and Sign capabilities (**[SC]**)
|
||||||
- A separate subkey with the Encryption capability (**[E]**)
|
- A separate subkey with the Encryption capability (**[E]**)
|
||||||
|
|
||||||
If you used the default parameters when generating your key, then that
|
If you used the default parameters when generating your key, then that
|
||||||
@ -192,9 +191,6 @@ for example::
|
|||||||
uid [ultimate] Alice Dev <adev@kernel.org>
|
uid [ultimate] Alice Dev <adev@kernel.org>
|
||||||
ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23]
|
ssb rsa2048 2018-01-23 [E] [expires: 2020-01-23]
|
||||||
|
|
||||||
Any key carrying the **[C]** capability is your master key, regardless
|
|
||||||
of any other capabilities it may have assigned to it.
|
|
||||||
|
|
||||||
The long line under the ``sec`` entry is your key fingerprint --
|
The long line under the ``sec`` entry is your key fingerprint --
|
||||||
whenever you see ``[fpr]`` in the examples below, that 40-character
|
whenever you see ``[fpr]`` in the examples below, that 40-character
|
||||||
string is what it refers to.
|
string is what it refers to.
|
||||||
@ -215,37 +211,30 @@ strong passphrase. To set it or change it, use::
|
|||||||
Create a separate Signing subkey
|
Create a separate Signing subkey
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
Our goal is to protect your master key by moving it to offline media, so
|
Our goal is to protect your Certify key by moving it to offline media,
|
||||||
if you only have a combined **[SC]** key, then you should create a separate
|
so if you only have a combined **[SC]** key, then you should create a
|
||||||
signing subkey::
|
separate signing subkey::
|
||||||
|
|
||||||
$ gpg --quick-addkey [fpr] ed25519 sign
|
$ gpg --quick-addkey [fpr] ed25519 sign
|
||||||
|
|
||||||
Remember to tell the keyservers about this change, so others can pull down
|
|
||||||
your new subkey::
|
|
||||||
|
|
||||||
$ gpg --send-key [fpr]
|
|
||||||
|
|
||||||
.. note:: ECC support in GnuPG
|
.. note:: ECC support in GnuPG
|
||||||
|
|
||||||
GnuPG 2.1 and later has full support for Elliptic Curve
|
GnuPG 2.1 and later has full support for Elliptic Curve
|
||||||
Cryptography, with ability to combine ECC subkeys with traditional
|
Cryptography, with ability to combine ECC subkeys with traditional
|
||||||
RSA master keys. The main upside of ECC cryptography is that it is
|
RSA keys. The main upside of ECC cryptography is that it is much
|
||||||
much faster computationally and creates much smaller signatures when
|
faster computationally and creates much smaller signatures when
|
||||||
compared byte for byte with 2048+ bit RSA keys. Unless you plan on
|
compared byte for byte with 2048+ bit RSA keys. Unless you plan on
|
||||||
using a smartcard device that does not support ECC operations, we
|
using a smartcard device that does not support ECC operations, we
|
||||||
recommend that you create an ECC signing subkey for your kernel
|
recommend that you create an ECC signing subkey for your kernel
|
||||||
work.
|
work.
|
||||||
|
|
||||||
If for some reason you prefer to stay with RSA subkeys, just replace
|
Note, that if you plan to use a hardware device that does not
|
||||||
"ed25519" with "rsa2048" in the above command. Additionally, if you
|
support ED25519 ECC keys, you should choose "nistp256" instead or
|
||||||
plan to use a hardware device that does not support ED25519 ECC
|
"ed25519."
|
||||||
keys, like Nitrokey Pro or a Yubikey, then you should use
|
|
||||||
"nistp256" instead or "ed25519."
|
|
||||||
|
|
||||||
|
|
||||||
Back up your master key for disaster recovery
|
Back up your Certify key for disaster recovery
|
||||||
---------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
The more signatures you have on your PGP key from other developers, the
|
The more signatures you have on your PGP key from other developers, the
|
||||||
more reasons you have to create a backup version that lives on something
|
more reasons you have to create a backup version that lives on something
|
||||||
@ -277,9 +266,7 @@ home, such as your bank vault.
|
|||||||
Your printer is probably no longer a simple dumb device connected to
|
Your printer is probably no longer a simple dumb device connected to
|
||||||
your parallel port, but since the output is still encrypted with
|
your parallel port, but since the output is still encrypted with
|
||||||
your passphrase, printing out even to "cloud-integrated" modern
|
your passphrase, printing out even to "cloud-integrated" modern
|
||||||
printers should remain a relatively safe operation. One option is to
|
printers should remain a relatively safe operation.
|
||||||
change the passphrase on your master key immediately after you are
|
|
||||||
done with paperkey.
|
|
||||||
|
|
||||||
Back up your whole GnuPG directory
|
Back up your whole GnuPG directory
|
||||||
----------------------------------
|
----------------------------------
|
||||||
@ -300,7 +287,7 @@ will use for backup purposes. You will need to encrypt them using LUKS
|
|||||||
-- refer to your distro's documentation on how to accomplish this.
|
-- refer to your distro's documentation on how to accomplish this.
|
||||||
|
|
||||||
For the encryption passphrase, you can use the same one as on your
|
For the encryption passphrase, you can use the same one as on your
|
||||||
master key.
|
PGP key.
|
||||||
|
|
||||||
Once the encryption process is over, re-insert the USB drive and make
|
Once the encryption process is over, re-insert the USB drive and make
|
||||||
sure it gets properly mounted. Copy your entire ``.gnupg`` directory
|
sure it gets properly mounted. Copy your entire ``.gnupg`` directory
|
||||||
@ -319,7 +306,7 @@ far away, because you'll need to use it every now and again for things
|
|||||||
like editing identities, adding or revoking subkeys, or signing other
|
like editing identities, adding or revoking subkeys, or signing other
|
||||||
people's keys.
|
people's keys.
|
||||||
|
|
||||||
Remove the master key from your homedir
|
Remove the Certify key from your homedir
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
The files in our home directory are not as well protected as we like to
|
The files in our home directory are not as well protected as we like to
|
||||||
@ -334,7 +321,7 @@ think. They can be leaked or stolen via many different means:
|
|||||||
Protecting your key with a good passphrase greatly helps reduce the risk
|
Protecting your key with a good passphrase greatly helps reduce the risk
|
||||||
of any of the above, but passphrases can be discovered via keyloggers,
|
of any of the above, but passphrases can be discovered via keyloggers,
|
||||||
shoulder-surfing, or any number of other means. For this reason, the
|
shoulder-surfing, or any number of other means. For this reason, the
|
||||||
recommended setup is to remove your master key from your home directory
|
recommended setup is to remove your Certify key from your home directory
|
||||||
and store it on offline storage.
|
and store it on offline storage.
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
@ -343,7 +330,7 @@ and store it on offline storage.
|
|||||||
your GnuPG directory in its entirety. What we are about to do will
|
your GnuPG directory in its entirety. What we are about to do will
|
||||||
render your key useless if you do not have a usable backup!
|
render your key useless if you do not have a usable backup!
|
||||||
|
|
||||||
First, identify the keygrip of your master key::
|
First, identify the keygrip of your Certify key::
|
||||||
|
|
||||||
$ gpg --with-keygrip --list-key [fpr]
|
$ gpg --with-keygrip --list-key [fpr]
|
||||||
|
|
||||||
@ -359,7 +346,7 @@ The output will be something like this::
|
|||||||
Keygrip = 3333000000000000000000000000000000000000
|
Keygrip = 3333000000000000000000000000000000000000
|
||||||
|
|
||||||
Find the keygrip entry that is beneath the ``pub`` line (right under the
|
Find the keygrip entry that is beneath the ``pub`` line (right under the
|
||||||
master key fingerprint). This will correspond directly to a file in your
|
Certify key fingerprint). This will correspond directly to a file in your
|
||||||
``~/.gnupg`` directory::
|
``~/.gnupg`` directory::
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
$ cd ~/.gnupg/private-keys-v1.d
|
||||||
@ -369,13 +356,13 @@ master key fingerprint). This will correspond directly to a file in your
|
|||||||
3333000000000000000000000000000000000000.key
|
3333000000000000000000000000000000000000.key
|
||||||
|
|
||||||
All you have to do is simply remove the .key file that corresponds to
|
All you have to do is simply remove the .key file that corresponds to
|
||||||
the master keygrip::
|
the Certify key keygrip::
|
||||||
|
|
||||||
$ cd ~/.gnupg/private-keys-v1.d
|
$ cd ~/.gnupg/private-keys-v1.d
|
||||||
$ rm 1111000000000000000000000000000000000000.key
|
$ rm 1111000000000000000000000000000000000000.key
|
||||||
|
|
||||||
Now, if you issue the ``--list-secret-keys`` command, it will show that
|
Now, if you issue the ``--list-secret-keys`` command, it will show that
|
||||||
the master key is missing (the ``#`` indicates it is not available)::
|
the Certify key is missing (the ``#`` indicates it is not available)::
|
||||||
|
|
||||||
$ gpg --list-secret-keys
|
$ gpg --list-secret-keys
|
||||||
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
|
sec# rsa2048 2018-01-24 [SC] [expires: 2020-01-24]
|
||||||
@ -404,7 +391,7 @@ file, which still contains your private keys.
|
|||||||
Move the subkeys to a dedicated crypto device
|
Move the subkeys to a dedicated crypto device
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
Even though the master key is now safe from being leaked or stolen, the
|
Even though the Certify key is now safe from being leaked or stolen, the
|
||||||
subkeys are still in your home directory. Anyone who manages to get
|
subkeys are still in your home directory. Anyone who manages to get
|
||||||
their hands on those will be able to decrypt your communication or fake
|
their hands on those will be able to decrypt your communication or fake
|
||||||
your signatures (if they know the passphrase). Furthermore, each time a
|
your signatures (if they know the passphrase). Furthermore, each time a
|
||||||
@ -447,7 +434,8 @@ functionality. There are several options available:
|
|||||||
- `Yubikey 5`_: proprietary hardware and software, but cheaper than
|
- `Yubikey 5`_: proprietary hardware and software, but cheaper than
|
||||||
Nitrokey Pro and comes available in the USB-C form that is more useful
|
Nitrokey Pro and comes available in the USB-C form that is more useful
|
||||||
with newer laptops. Offers additional security features such as FIDO
|
with newer laptops. Offers additional security features such as FIDO
|
||||||
U2F, among others, and now finally supports ECC keys (NISTP).
|
U2F, among others, and now finally supports NISTP and ED25519 ECC
|
||||||
|
keys.
|
||||||
|
|
||||||
`LWN has a good review`_ of some of the above models, as well as several
|
`LWN has a good review`_ of some of the above models, as well as several
|
||||||
others. Your choice will depend on cost, shipping availability in your
|
others. Your choice will depend on cost, shipping availability in your
|
||||||
@ -460,7 +448,7 @@ geographical region, and open/proprietary hardware considerations.
|
|||||||
Foundation.
|
Foundation.
|
||||||
|
|
||||||
.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6
|
.. _`Nitrokey Start`: https://shop.nitrokey.com/shop/product/nitrokey-start-6
|
||||||
.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nitrokey-pro-2-3
|
.. _`Nitrokey Pro 2`: https://shop.nitrokey.com/shop/product/nkpr2-nitrokey-pro-2-3
|
||||||
.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/
|
.. _`Yubikey 5`: https://www.yubico.com/products/yubikey-5-overview/
|
||||||
.. _Gnuk: https://www.fsij.org/doc-gnuk/
|
.. _Gnuk: https://www.fsij.org/doc-gnuk/
|
||||||
.. _`LWN has a good review`: https://lwn.net/Articles/736231/
|
.. _`LWN has a good review`: https://lwn.net/Articles/736231/
|
||||||
@ -627,10 +615,10 @@ Other common GnuPG operations
|
|||||||
Here is a quick reference for some common operations you'll need to do
|
Here is a quick reference for some common operations you'll need to do
|
||||||
with your PGP key.
|
with your PGP key.
|
||||||
|
|
||||||
Mounting your master key offline storage
|
Mounting your safe offline storage
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
You will need your master key for any of the operations below, so you
|
You will need your Certify key for any of the operations below, so you
|
||||||
will first need to mount your backup offline storage and tell GnuPG to
|
will first need to mount your backup offline storage and tell GnuPG to
|
||||||
use it::
|
use it::
|
||||||
|
|
||||||
@ -644,7 +632,7 @@ your regular home directory location).
|
|||||||
Extending key expiration date
|
Extending key expiration date
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The master key has the default expiration date of 2 years from the date
|
The Certify key has the default expiration date of 2 years from the date
|
||||||
of creation. This is done both for security reasons and to make obsolete
|
of creation. This is done both for security reasons and to make obsolete
|
||||||
keys eventually disappear from keyservers.
|
keys eventually disappear from keyservers.
|
||||||
|
|
||||||
@ -685,6 +673,7 @@ remote end.
|
|||||||
|
|
||||||
.. _`Agent Forwarding over SSH`: https://wiki.gnupg.org/AgentForwarding
|
.. _`Agent Forwarding over SSH`: https://wiki.gnupg.org/AgentForwarding
|
||||||
|
|
||||||
|
.. _pgp_with_git:
|
||||||
|
|
||||||
Using PGP with Git
|
Using PGP with Git
|
||||||
==================
|
==================
|
||||||
@ -828,6 +817,63 @@ You can tell git to always sign commits::
|
|||||||
|
|
||||||
.. _verify_identities:
|
.. _verify_identities:
|
||||||
|
|
||||||
|
|
||||||
|
How to work with signed patches
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
It is possible to use your PGP key to sign patches sent to kernel
|
||||||
|
developer mailing lists. Since existing email signature mechanisms
|
||||||
|
(PGP-Mime or PGP-inline) tend to cause problems with regular code
|
||||||
|
review tasks, you should use the tool kernel.org created for this
|
||||||
|
purpose that puts cryptographic attestation signatures into message
|
||||||
|
headers (a-la DKIM):
|
||||||
|
|
||||||
|
- `Patatt Patch Attestation`_
|
||||||
|
|
||||||
|
.. _`Patatt Patch Attestation`: https://pypi.org/project/patatt/
|
||||||
|
|
||||||
|
Installing and configuring patatt
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Patatt is packaged for many distributions already, so please check there
|
||||||
|
first. You can also install it from pypi using "``pip install patatt``".
|
||||||
|
|
||||||
|
If you already have your PGP key configured with git (via the
|
||||||
|
``user.signingKey`` configuration parameter), then patatt requires no
|
||||||
|
further configuration. You can start signing your patches by installing
|
||||||
|
the git-send-email hook in the repository you want::
|
||||||
|
|
||||||
|
patatt install-hook
|
||||||
|
|
||||||
|
Now any patches you send with ``git send-email`` will be automatically
|
||||||
|
signed with your cryptographic signature.
|
||||||
|
|
||||||
|
Checking patatt signatures
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
If you are using ``b4`` to retrieve and apply patches, then it will
|
||||||
|
automatically attempt to verify all DKIM and patatt signatures it
|
||||||
|
encounters, for example::
|
||||||
|
|
||||||
|
$ b4 am 20220720205013.890942-1-broonie@kernel.org
|
||||||
|
[...]
|
||||||
|
Checking attestation on all messages, may take a moment...
|
||||||
|
---
|
||||||
|
✓ [PATCH v1 1/3] kselftest/arm64: Correct buffer allocation for SVE Z registers
|
||||||
|
✓ [PATCH v1 2/3] arm64/sve: Document our actual ABI for clearing registers on syscall
|
||||||
|
✓ [PATCH v1 3/3] kselftest/arm64: Enforce actual ABI for SVE syscalls
|
||||||
|
---
|
||||||
|
✓ Signed: openpgp/broonie@kernel.org
|
||||||
|
✓ Signed: DKIM/kernel.org
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Patatt and b4 are still in active development and you should check
|
||||||
|
the latest documentation for these projects for any new or updated
|
||||||
|
features.
|
||||||
|
|
||||||
|
.. _kernel_identities:
|
||||||
|
|
||||||
How to verify kernel developer identities
|
How to verify kernel developer identities
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
@ -899,65 +945,17 @@ the new default in GnuPG v2). To set it, add (or modify) the
|
|||||||
|
|
||||||
trust-model tofu+pgp
|
trust-model tofu+pgp
|
||||||
|
|
||||||
How to use keyservers (more) safely
|
Using the kernel.org web of trust repository
|
||||||
-----------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
If you get a "No public key" error when trying to validate someone's
|
Kernel.org maintains a git repository with developers' public keys as a
|
||||||
tag, then you should attempt to lookup that key using a keyserver. It is
|
replacement for replicating keyserver networks that have gone mostly
|
||||||
important to keep in mind that there is absolutely no guarantee that the
|
dark in the past few years. The full documentation for how to set up
|
||||||
key you retrieve from PGP keyservers belongs to the actual person --
|
that repository as your source of public keys can be found here:
|
||||||
that much is by design. You are supposed to use the Web of Trust to
|
|
||||||
establish key validity.
|
|
||||||
|
|
||||||
How to properly maintain the Web of Trust is beyond the scope of this
|
- `Kernel developer PGP Keyring`_
|
||||||
document, simply because doing it properly requires both effort and
|
|
||||||
dedication that tends to be beyond the caring threshold of most human
|
|
||||||
beings. Here are some shortcuts that will help you reduce the risk of
|
|
||||||
importing a malicious key.
|
|
||||||
|
|
||||||
First, let's say you've tried to run ``git verify-tag`` but it returned
|
If you are a kernel developer, please consider submitting your key for
|
||||||
an error saying the key is not found::
|
inclusion into that keyring.
|
||||||
|
|
||||||
$ git verify-tag sunxi-fixes-for-4.15-2
|
.. _`Kernel developer PGP Keyring`: https://korg.docs.kernel.org/pgpkeys.html
|
||||||
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
|
|
||||||
|
|
||||||
Let's query the keyserver for more info about that key fingerprint (the
|
|
||||||
fingerprint probably belongs to a subkey, so we can't use it directly
|
|
||||||
without finding out the ID of the master key it is associated with)::
|
|
||||||
|
|
||||||
$ 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
|
|
||||||
|
|
||||||
Locate the ID of the master key in the output, in our example
|
|
||||||
``C94035C21B4F2AEB``. Now display the key of Linus Torvalds that you
|
|
||||||
have on your keyring::
|
|
||||||
|
|
||||||
$ 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]
|
|
||||||
|
|
||||||
Next, find a trust path from Linus Torvalds to the key-id you found via ``gpg
|
|
||||||
--search`` of the unknown key. For this, you can use several tools including
|
|
||||||
https://github.com/mricon/wotmate,
|
|
||||||
https://git.kernel.org/pub/scm/docs/kernel/pgpkeys.git/tree/graphs, and
|
|
||||||
https://the.earth.li/~noodles/pathfind.html.
|
|
||||||
|
|
||||||
If you get a few decent trust paths, then it's a pretty good indication
|
|
||||||
that it is a valid key. You can add it to your keyring from the
|
|
||||||
keyserver now::
|
|
||||||
|
|
||||||
$ gpg --recv-key C94035C21B4F2AEB
|
|
||||||
|
|
||||||
This process is not perfect, and you are obviously trusting the
|
|
||||||
administrators of the PGP Pathfinder service to not be malicious (in
|
|
||||||
fact, this goes against :ref:`devs_not_infra`). However, if you
|
|
||||||
do not carefully maintain your own web of trust, then it is a marked
|
|
||||||
improvement over blindly trusting keyservers.
|
|
||||||
|
@ -97,6 +97,12 @@ text, like this:
|
|||||||
|
|
||||||
commit <sha1> upstream.
|
commit <sha1> upstream.
|
||||||
|
|
||||||
|
or alternatively:
|
||||||
|
|
||||||
|
.. code-block:: none
|
||||||
|
|
||||||
|
[ Upstream commit <sha1> ]
|
||||||
|
|
||||||
Additionally, some patches submitted via :ref:`option_1` may have additional
|
Additionally, some patches submitted via :ref:`option_1` may have additional
|
||||||
patch prerequisites which can be cherry-picked. This can be specified in the
|
patch prerequisites which can be cherry-picked. This can be specified in the
|
||||||
following format in the sign-off area:
|
following format in the sign-off area:
|
||||||
|
@ -715,8 +715,8 @@ references.
|
|||||||
|
|
||||||
.. _backtraces:
|
.. _backtraces:
|
||||||
|
|
||||||
Backtraces in commit mesages
|
Backtraces in commit messages
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Backtraces help document the call chain leading to a problem. However,
|
Backtraces help document the call chain leading to a problem. However,
|
||||||
not all backtraces are helpful. For example, early boot call chains are
|
not all backtraces are helpful. For example, early boot call chains are
|
||||||
|
@ -94,7 +94,7 @@ other HZ detail. Thus the CFS scheduler has no notion of "timeslices" in the
|
|||||||
way the previous scheduler had, and has no heuristics whatsoever. There is
|
way the previous scheduler had, and has no heuristics whatsoever. There is
|
||||||
only one central tunable (you have to switch on CONFIG_SCHED_DEBUG):
|
only one central tunable (you have to switch on CONFIG_SCHED_DEBUG):
|
||||||
|
|
||||||
/proc/sys/kernel/sched_min_granularity_ns
|
/sys/kernel/debug/sched/min_granularity_ns
|
||||||
|
|
||||||
which can be used to tune the scheduler from "desktop" (i.e., low latencies) to
|
which can be used to tune the scheduler from "desktop" (i.e., low latencies) to
|
||||||
"server" (i.e., good batching) workloads. It defaults to a setting suitable
|
"server" (i.e., good batching) workloads. It defaults to a setting suitable
|
||||||
|
@ -14,45 +14,3 @@ Unsorted Documentation
|
|||||||
static-keys
|
static-keys
|
||||||
tee
|
tee
|
||||||
xz
|
xz
|
||||||
|
|
||||||
Atomic Types
|
|
||||||
============
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\footnotesize
|
|
||||||
|
|
||||||
.. include:: ../atomic_t.txt
|
|
||||||
:literal:
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\normalsize
|
|
||||||
|
|
||||||
Atomic bitops
|
|
||||||
=============
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\footnotesize
|
|
||||||
|
|
||||||
.. include:: ../atomic_bitops.txt
|
|
||||||
:literal:
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\normalsize
|
|
||||||
|
|
||||||
Memory Barriers
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\footnotesize
|
|
||||||
|
|
||||||
.. include:: ../memory-barriers.txt
|
|
||||||
:literal:
|
|
||||||
|
|
||||||
.. raw:: latex
|
|
||||||
|
|
||||||
\normalsize
|
|
||||||
|
58
Documentation/subsystem-apis.rst
Normal file
58
Documentation/subsystem-apis.rst
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
==============================
|
||||||
|
Kernel subsystem documentation
|
||||||
|
==============================
|
||||||
|
|
||||||
|
These books get into the details of how specific kernel subsystems work
|
||||||
|
from the point of view of a kernel developer. Much of the information here
|
||||||
|
is taken directly from the kernel source, with supplemental material added
|
||||||
|
as needed (or at least as we managed to add it — probably *not* all that is
|
||||||
|
needed).
|
||||||
|
|
||||||
|
**Fixme**: much more organizational work is needed here.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
|
||||||
|
driver-api/index
|
||||||
|
core-api/index
|
||||||
|
locking/index
|
||||||
|
accounting/index
|
||||||
|
block/index
|
||||||
|
cdrom/index
|
||||||
|
cpu-freq/index
|
||||||
|
fb/index
|
||||||
|
fpga/index
|
||||||
|
hid/index
|
||||||
|
i2c/index
|
||||||
|
iio/index
|
||||||
|
isdn/index
|
||||||
|
infiniband/index
|
||||||
|
leds/index
|
||||||
|
netlabel/index
|
||||||
|
networking/index
|
||||||
|
pcmcia/index
|
||||||
|
power/index
|
||||||
|
target/index
|
||||||
|
timers/index
|
||||||
|
spi/index
|
||||||
|
w1/index
|
||||||
|
watchdog/index
|
||||||
|
virt/index
|
||||||
|
input/index
|
||||||
|
hwmon/index
|
||||||
|
gpu/index
|
||||||
|
security/index
|
||||||
|
sound/index
|
||||||
|
crypto/index
|
||||||
|
filesystems/index
|
||||||
|
mm/index
|
||||||
|
bpf/index
|
||||||
|
usb/index
|
||||||
|
PCI/index
|
||||||
|
scsi/index
|
||||||
|
misc-devices/index
|
||||||
|
scheduler/index
|
||||||
|
mhi/index
|
||||||
|
peci/index
|
@ -412,7 +412,7 @@ Extended error information
|
|||||||
Because the default sort key above is 'hitcount', the above shows a
|
Because the default sort key above is 'hitcount', the above shows a
|
||||||
the list of call_sites by increasing hitcount, so that at the bottom
|
the list of call_sites by increasing hitcount, so that at the bottom
|
||||||
we see the functions that made the most kmalloc calls during the
|
we see the functions that made the most kmalloc calls during the
|
||||||
run. If instead we we wanted to see the top kmalloc callers in
|
run. If instead we wanted to see the top kmalloc callers in
|
||||||
terms of the number of bytes requested rather than the number of
|
terms of the number of bytes requested rather than the number of
|
||||||
calls, and we wanted the top caller to appear at the top, we can use
|
calls, and we wanted the top caller to appear at the top, we can use
|
||||||
the 'sort' parameter, along with the 'descending' modifier::
|
the 'sort' parameter, along with the 'descending' modifier::
|
||||||
|
@ -328,8 +328,8 @@ Configuring Kprobes
|
|||||||
===================
|
===================
|
||||||
|
|
||||||
When configuring the kernel using make menuconfig/xconfig/oldconfig,
|
When configuring the kernel using make menuconfig/xconfig/oldconfig,
|
||||||
ensure that CONFIG_KPROBES is set to "y". Under "General setup", look
|
ensure that CONFIG_KPROBES is set to "y", look for "Kprobes" under
|
||||||
for "Kprobes".
|
"General architecture-dependent options".
|
||||||
|
|
||||||
So that you can load and unload Kprobes-based instrumentation modules,
|
So that you can load and unload Kprobes-based instrumentation modules,
|
||||||
make sure "Loadable module support" (CONFIG_MODULES) and "Module
|
make sure "Loadable module support" (CONFIG_MODULES) and "Module
|
||||||
|
@ -20,7 +20,7 @@ For example::
|
|||||||
[root@f32 ~]# cd /sys/kernel/tracing/
|
[root@f32 ~]# cd /sys/kernel/tracing/
|
||||||
[root@f32 tracing]# echo timerlat > current_tracer
|
[root@f32 tracing]# echo timerlat > current_tracer
|
||||||
|
|
||||||
It is possible to follow the trace by reading the trace trace file::
|
It is possible to follow the trace by reading the trace file::
|
||||||
|
|
||||||
[root@f32 tracing]# cat trace
|
[root@f32 tracing]# cat trace
|
||||||
# tracer: timerlat
|
# tracer: timerlat
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
Chinese translated version of Documentation/core-api/irq/index.rst
|
|
||||||
|
|
||||||
If you have any comment or update to the content, please contact the
|
|
||||||
original document maintainer directly. However, if you have a problem
|
|
||||||
communicating in English you can also ask the Chinese maintainer for
|
|
||||||
help. Contact the Chinese maintainer if this translation is outdated
|
|
||||||
or if there is a problem with the translation.
|
|
||||||
|
|
||||||
Maintainer: Eric W. Biederman <ebiederman@xmission.com>
|
|
||||||
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
Documentation/core-api/irq/index.rst 的中文翻译
|
|
||||||
|
|
||||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
|
||||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
|
||||||
译存在问题,请联系中文版维护者。
|
|
||||||
英文版维护者: Eric W. Biederman <ebiederman@xmission.com>
|
|
||||||
中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
|
|
||||||
|
|
||||||
以下为正文
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
何为 IRQ?
|
|
||||||
|
|
||||||
一个 IRQ 是来自某个设备的一个中断请求。目前,它们可以来自一个硬件引脚,
|
|
||||||
或来自一个数据包。多个设备可能连接到同个硬件引脚,从而共享一个 IRQ。
|
|
||||||
|
|
||||||
一个 IRQ 编号是用于告知硬件中断源的内核标识。通常情况下,这是一个
|
|
||||||
全局 irq_desc 数组的索引,但是除了在 linux/interrupt.h 中的实现,
|
|
||||||
具体的细节是体系结构特定的。
|
|
||||||
|
|
||||||
一个 IRQ 编号是设备上某个可能的中断源的枚举。通常情况下,枚举的编号是
|
|
||||||
该引脚在系统内中断控制器的所有输入引脚中的编号。对于 ISA 总线中的情况,
|
|
||||||
枚举的是在两个 i8259 中断控制器中 16 个输入引脚。
|
|
||||||
|
|
||||||
架构可以对 IRQ 编号指定额外的含义,在硬件涉及任何手工配置的情况下,
|
|
||||||
是被提倡的。ISA 的 IRQ 是一个分配这类额外含义的典型例子。
|
|
139
Documentation/translations/zh_CN/PCI/acpi-info.rst
Normal file
139
Documentation/translations/zh_CN/PCI/acpi-info.rst
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/PCI/acpi-info.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
|
||||||
|
=====================
|
||||||
|
PCI主桥的ACPI注意事项
|
||||||
|
=====================
|
||||||
|
|
||||||
|
一般的规则是,ACPI命名空间应该描述操作系统可能使用的所有东西,除非有其他方法让操作系
|
||||||
|
统找到它[1, 2]。
|
||||||
|
|
||||||
|
例如,没有标准的硬件机制来枚举PCI主桥,所以ACPI命名空间必须描述每个主桥、访问它
|
||||||
|
下面的PCI配置空间的方法、主桥转发到PCI的地址空间窗口(使用_CRS)以及传统的INTx
|
||||||
|
中断的路由(使用_PRT)。
|
||||||
|
|
||||||
|
在主桥下面的PCI设备,通常不需要通过ACPI描述。操作系统可以通过标准的PCI枚举机制来
|
||||||
|
发现它们,使用配置访问来发现和识别设备,并读取和测量它们的BAR。然而,如果ACPI为它们
|
||||||
|
提供电源管理或热插拔功能,或者如果设备有由平台中断控制器连接的INTx中断,需要一个_PRT
|
||||||
|
来描述这些连接,这种情况下ACPI可以描述PCI设备。
|
||||||
|
|
||||||
|
ACPI资源描述是通过ACPI命名空间中设备的_CRS对象完成的[2]。_CRS就像一个通用的PCI BAR:
|
||||||
|
操作系统可以读取_CRS并找出正在消耗的资源,即使它没有该设备的驱动程序[3]。这一点很重要,
|
||||||
|
因为它意味着一个旧的操作系统可以正确地工作,即使是在操作系统不知道的新设备的系统上。新设
|
||||||
|
备可能什么都不做,但操作系统至少可以确保没有资源与它们冲突。
|
||||||
|
|
||||||
|
像MCFG、HPET、ECDT等静态表,不是保留地址空间的机制。静态表是在操作系统在启动初期且在它
|
||||||
|
能够解析ACPI命名空间之前需要知道的东西。如果定义了一个新的表,即使旧的操作系统忽略了这
|
||||||
|
个表,它也需要正常运行。_CRS允许这样做,因为它是通用的,可以被旧的操作系统解析;而静态表
|
||||||
|
则不允许。
|
||||||
|
|
||||||
|
如果操作系统要管理一个通过ACPI描述的不可发现的设备,该设备将有一个特定的_HID/_CID,以
|
||||||
|
告诉操作系统与之绑定的驱动程序,并且_CRS告诉操作系统和驱动程序该设备的寄存器在哪里。
|
||||||
|
|
||||||
|
PCI主桥是PNP0A03或PNP0A08设备。它们的_CRS应该描述它们所消耗的所有地址空间。这包括它
|
||||||
|
们转发到PCI总线上的所有窗口,以及不转发到PCI的主桥本身的寄存器。主桥的寄存器包括次要/下
|
||||||
|
级总线寄存器,决定了桥下面的总线范围,窗口寄存器描述了桥洞,等等。这些都是设备相关的,非
|
||||||
|
架构相关的东西,所以PNP0A03/PNP0A08驱动可以管理它们的唯一方法是通过_PRS/_CRS/_SRS,
|
||||||
|
它包含了特定于设备的细节。主桥寄存器也包括ECAM空间,因为它是由主桥消耗的。
|
||||||
|
|
||||||
|
ACPI定义了一个Consumer/Producer位来区分桥寄存器(“Consumer”下文译作消费者)和
|
||||||
|
桥洞(“Producer”下文译作生产者)[4, 5],但是早期的BIOS没有正确使用这个位。其结果
|
||||||
|
是,目前的ACPI规范只为扩展地址空间描述符定义了消费者/生产者;在旧的QWord/Word/Word地
|
||||||
|
址空间描述符中,该位应该被忽略。因此,操作系统必须假定所有的QWord/Word/Word描述符都是
|
||||||
|
窗口。
|
||||||
|
|
||||||
|
在增加扩展地址空间描述符之前,消费者/生产者的失败意味着没有办法描述PNP0A03/PNP0A08设
|
||||||
|
备本身的桥寄存器。解决办法是在PNP0C02捕捉器中描述桥寄存器(包括ECAM空间)[6]。
|
||||||
|
除了ECAM之外,桥寄存器空间反正是特定于设备的,所以通用的PNP0A03/PNP0A08驱动程
|
||||||
|
序(pci_root.c)没有必要了解它。
|
||||||
|
|
||||||
|
新的架构应该能够在PNP0A03设备中使用“消费者”扩展地址空间描述符,用于桥寄存器,包括
|
||||||
|
ECAM,尽管对[6]的严格解释可能禁止这样做。旧的x86和ia64内核假定所有的地址空间描述
|
||||||
|
符,包括“消费者”扩展地址空间的描述符,都是窗口,所以在这些架构上以这种方式描述桥寄
|
||||||
|
存器是不安全的。
|
||||||
|
|
||||||
|
PNP0C02“主板”设备基本上是万能的。除了“不要将这些资源用于其他用途”之外,没有其他的编
|
||||||
|
程模型。因此,PNP0C02 _CRS应该声明ACPI命名空间中(1)没有被_CRS声明的任何其他设备对
|
||||||
|
象的地址空间,(2)不应该被OS分配给其他东西。
|
||||||
|
|
||||||
|
除非有一个标准的固件接口用于配置访问,例如ia64 SAL接口[7],否则PCIe规范要求使用增强
|
||||||
|
型配置访问方法(ECAM)。主桥消耗ECAM内存地址空间并将内存访问转换为PCI配置访问。该规范
|
||||||
|
定义了ECAM地址空间的布局和功能;只有地址空间的基础是特定于设备的。ACPI操作系统从静态
|
||||||
|
MCFG表或PNP0A03设备中的_CBA方法中了解基础地址。
|
||||||
|
|
||||||
|
MCFG表必须描述非热插拔主桥的ECAM空间[8]。由于MCFG是一个静态表,不能通过热插拔更新,
|
||||||
|
PNP0A03设备中的_CBA方法描述了可热插拔主桥的ECAM空间[9]。请注意,对于MCFG和_CBA,
|
||||||
|
基址总是对应于总线0,即使桥器下面的总线范围(通过_CRS报告)不从0开始。
|
||||||
|
|
||||||
|
|
||||||
|
[1] ACPI 6.2, sec 6.1:
|
||||||
|
对于任何在非枚举类型的总线上的设备(例如,ISA总线),OSPM会枚举设备的标识符,ACPI
|
||||||
|
系统固件必须为每个设备提供一个_HID对象...以使OSPM能够做到这一点。
|
||||||
|
|
||||||
|
[2] ACPI 6.2, sec 3.7:
|
||||||
|
操作系统枚举主板设备时,只需通过读取ACPI命名空间来寻找具有硬件ID的设备。
|
||||||
|
|
||||||
|
ACPI枚举的每个设备都包括ACPI命名空间中ACPI定义的对象,该对象报告设备可能占用的硬
|
||||||
|
件资源[_PRS],报告设备当前使用的资源[_CRS]的对象,以及配置这些资源的对象[_SRS]。
|
||||||
|
这些信息被即插即用操作系统(OSPM)用来配置设备。
|
||||||
|
|
||||||
|
[3] ACPI 6.2, sec 6.2:
|
||||||
|
OSPM使用设备配置对象来配置通过ACPI列举的设备的硬件资源。设备配置对象提供了关于当前
|
||||||
|
和可能的资源需求的信息,共享资源之间的关系,以及配置硬件资源的方法。
|
||||||
|
|
||||||
|
当OSPM枚举一个设备时,它调用_PRS来确定该设备的资源需求。它也可以调用_CRS来找到该设
|
||||||
|
备的当前资源设置。利用这些信息,即插即用系统决定设备应该消耗什么资源,并通过调用设备
|
||||||
|
的_SRS控制方法来设置这些资源。
|
||||||
|
|
||||||
|
在ACPI中,设备可以消耗资源(例如,传统的键盘),提供资源(例如,一个专有的PCI桥),
|
||||||
|
或者两者都做。除非另有规定,设备的资源被假定为来自设备层次结构中设备上方最近的匹配资
|
||||||
|
源。
|
||||||
|
|
||||||
|
[4] ACPI 6.2, sec 6.4.3.5.1, 2, 3, 4:
|
||||||
|
QWord/DWord/Word 地址空间描述符 (.1, .2, .3)
|
||||||
|
常规标志: Bit [0] 被忽略。
|
||||||
|
|
||||||
|
扩展地址空间描述符 (.4)
|
||||||
|
常规标志: Bit [0] 消费者/生产者:
|
||||||
|
|
||||||
|
* 1 – 这个设备消费这个资源
|
||||||
|
* 0 – 该设备生产和消费该资源
|
||||||
|
|
||||||
|
[5] ACPI 6.2, sec 19.6.43:
|
||||||
|
ResourceUsage指定内存范围是由这个设备(ResourceConsumer)消费还是传递给子设备
|
||||||
|
(ResourceProducer)。如果没有指定,那么就假定是ResourceConsumer。
|
||||||
|
|
||||||
|
[6] PCI Firmware 3.2, sec 4.1.2:
|
||||||
|
如果操作系统不能原生的懂得保留MMCFG区域,MMCFG区域必须由固件保留。在MCFG表中或通
|
||||||
|
过_CBA方法(见第4.1.3节)报告的地址范围必须通过声明主板资源来保留。对于大多数系统,
|
||||||
|
主板资源将出现在ACPI命名空间的根部(在_SB下),在一个节点的_HID为EISAID(PNP0C0
|
||||||
|
2),在这种情况下的资源不应该要求在根PCI总线的_CRS。这些资源可以选择在Int15 E820
|
||||||
|
或EFIGetMemoryMap中作为保留内存返回,但必须始终通过ACPI作为主板资源报告。
|
||||||
|
|
||||||
|
[7] PCI Express 4.0, sec 7.2.2:
|
||||||
|
对于PC兼容的系统,或者没有实现允许访问配置空间的处理器架构特定固件接口标准的系统,需
|
||||||
|
要使用本节中定义的ECAM。
|
||||||
|
|
||||||
|
[8] PCI Firmware 3.2, sec 4.1.2:
|
||||||
|
MCFG表是一个ACPI表,用于沟通的基础地址对应的非热的可移动的PCI段组范围内的PCI段组在
|
||||||
|
启动时提供给操作系统。这对PC兼容系统来说是必需的。
|
||||||
|
|
||||||
|
MCFG表仅用于沟通在启动时系统可用的PCI段组对应的基址。
|
||||||
|
|
||||||
|
[9] PCI Firmware 3.2, sec 4.1.3:
|
||||||
|
_CBA (Memory mapped Configuration Base Address) 控制方法是一个可选的ACPI对
|
||||||
|
象,用于返回热插拔主桥的64位内存映射的配置基址。_CBA 返回的基址是与处理器相关的地址。
|
||||||
|
_CBA 控制方法被评估为一个整数。
|
||||||
|
|
||||||
|
这个控制方法出现在主桥对象下。当_CBA方法出现在一个活动的主桥对象下时,操作系统会评
|
||||||
|
估这个结构,以确定内存映射的配置基址,对应于_CRS方法中指定的总线编号范围的PCI段组。
|
||||||
|
一个包含_CBA方法的ACPI命名空间对象也必须包含一个相应的_SEG方法。
|
@ -10,9 +10,6 @@
|
|||||||
:校译:
|
:校译:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. _cn_PCI_index.rst:
|
|
||||||
|
|
||||||
===================
|
===================
|
||||||
Linux PCI总线子系统
|
Linux PCI总线子系统
|
||||||
===================
|
===================
|
||||||
@ -26,12 +23,12 @@ Linux PCI总线子系统
|
|||||||
pci-iov-howto
|
pci-iov-howto
|
||||||
msi-howto
|
msi-howto
|
||||||
sysfs-pci
|
sysfs-pci
|
||||||
|
acpi-info
|
||||||
|
|
||||||
|
|
||||||
Todolist:
|
Todolist:
|
||||||
|
|
||||||
acpi-info
|
* pci-error-recovery
|
||||||
pci-error-recovery
|
* pcieaer-howto
|
||||||
pcieaer-howto
|
* endpoint/index
|
||||||
endpoint/index
|
* boot-interrupts
|
||||||
boot-interrupts
|
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
吴想成 Wu XiangCheng <bobwxc@email.cn>
|
吴想成 Wu XiangCheng <bobwxc@email.cn>
|
||||||
|
|
||||||
Linux内核5.x版本 <http://kernel.org/>
|
Linux内核6.x版本 <http://kernel.org/>
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
以下是Linux版本5的发行注记。仔细阅读它们,
|
以下是Linux版本6的发行注记。仔细阅读它们,
|
||||||
它们会告诉你这些都是什么,解释如何安装内核,以及遇到问题时该如何做。
|
它们会告诉你这些都是什么,解释如何安装内核,以及遇到问题时该如何做。
|
||||||
|
|
||||||
什么是Linux?
|
什么是Linux?
|
||||||
@ -61,27 +61,27 @@ Linux内核5.x版本 <http://kernel.org/>
|
|||||||
- 如果您要安装完整的源代码,请把内核tar档案包放在您有权限的目录中(例如您
|
- 如果您要安装完整的源代码,请把内核tar档案包放在您有权限的目录中(例如您
|
||||||
的主目录)并将其解包::
|
的主目录)并将其解包::
|
||||||
|
|
||||||
xz -cd linux-5.x.tar.xz | tar xvf -
|
xz -cd linux-6.x.tar.xz | tar xvf -
|
||||||
|
|
||||||
将“X”替换成最新内核的版本号。
|
将“X”替换成最新内核的版本号。
|
||||||
|
|
||||||
【不要】使用 /usr/src/linux 目录!这里有一组库头文件使用的内核头文件
|
【不要】使用 /usr/src/linux 目录!这里有一组库头文件使用的内核头文件
|
||||||
(通常是不完整的)。它们应该与库匹配,而不是被内核的变化搞得一团糟。
|
(通常是不完整的)。它们应该与库匹配,而不是被内核的变化搞得一团糟。
|
||||||
|
|
||||||
- 您还可以通过打补丁在5.x版本之间升级。补丁以xz格式分发。要通过打补丁进行
|
- 您还可以通过打补丁在6.x版本之间升级。补丁以xz格式分发。要通过打补丁进行
|
||||||
安装,请获取所有较新的补丁文件,进入内核源代码(linux-5.x)的目录并
|
安装,请获取所有较新的补丁文件,进入内核源代码(linux-6.x)的目录并
|
||||||
执行::
|
执行::
|
||||||
|
|
||||||
xz -cd ../patch-5.x.xz | patch -p1
|
xz -cd ../patch-6.x.xz | patch -p1
|
||||||
|
|
||||||
请【按顺序】替换所有大于当前源代码树版本的“x”,这样就可以了。您可能想要
|
请【按顺序】替换所有大于当前源代码树版本的“x”,这样就可以了。您可能想要
|
||||||
删除备份文件(文件名类似xxx~ 或 xxx.orig),并确保没有失败的补丁(文件名
|
删除备份文件(文件名类似xxx~ 或 xxx.orig),并确保没有失败的补丁(文件名
|
||||||
类似xxx# 或 xxx.rej)。如果有,不是你就是我犯了错误。
|
类似xxx# 或 xxx.rej)。如果有,不是你就是我犯了错误。
|
||||||
|
|
||||||
与5.x内核的补丁不同,5.x.y内核(也称为稳定版内核)的补丁不是增量的,而是
|
与6.x内核的补丁不同,6.x.y内核(也称为稳定版内核)的补丁不是增量的,而是
|
||||||
直接应用于基本的5.x内核。例如,如果您的基本内核是5.0,并且希望应用5.0.3
|
直接应用于基本的6.x内核。例如,如果您的基本内核是6.0,并且希望应用6.0.3
|
||||||
补丁,则不应先应用5.0.1和5.0.2的补丁。类似地,如果您运行的是5.0.2内核,
|
补丁,则不应先应用6.0.1和6.0.2的补丁。类似地,如果您运行的是6.0.2内核,
|
||||||
并且希望跳转到5.0.3,那么在应用5.0.3补丁之前,必须首先撤销5.0.2补丁
|
并且希望跳转到6.0.3,那么在应用6.0.3补丁之前,必须首先撤销6.0.2补丁
|
||||||
(即patch -R)。更多关于这方面的内容,请阅读
|
(即patch -R)。更多关于这方面的内容,请阅读
|
||||||
:ref:`Documentation/process/applying-patches.rst <applying_patches>` 。
|
:ref:`Documentation/process/applying-patches.rst <applying_patches>` 。
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ Linux内核5.x版本 <http://kernel.org/>
|
|||||||
软件要求
|
软件要求
|
||||||
---------
|
---------
|
||||||
|
|
||||||
编译和运行5.x内核需要各种软件包的最新版本。请参考
|
编译和运行6.x内核需要各种软件包的最新版本。请参考
|
||||||
:ref:`Documentation/process/changes.rst <changes>`
|
:ref:`Documentation/process/changes.rst <changes>`
|
||||||
来了解最低版本要求以及如何升级软件包。请注意,使用过旧版本的这些包可能会
|
来了解最低版本要求以及如何升级软件包。请注意,使用过旧版本的这些包可能会
|
||||||
导致很难追踪的间接错误,因此不要以为在生成或操作过程中出现明显问题时可以
|
导致很难追踪的间接错误,因此不要以为在生成或操作过程中出现明显问题时可以
|
||||||
@ -116,12 +116,12 @@ Linux内核5.x版本 <http://kernel.org/>
|
|||||||
``make O=output/dir`` 选项可以为输出文件(包括 .config)指定备用位置。
|
``make O=output/dir`` 选项可以为输出文件(包括 .config)指定备用位置。
|
||||||
例如::
|
例如::
|
||||||
|
|
||||||
kernel source code: /usr/src/linux-5.x
|
kernel source code: /usr/src/linux-6.x
|
||||||
build directory: /home/name/build/kernel
|
build directory: /home/name/build/kernel
|
||||||
|
|
||||||
要配置和构建内核,请使用::
|
要配置和构建内核,请使用::
|
||||||
|
|
||||||
cd /usr/src/linux-5.x
|
cd /usr/src/linux-6.x
|
||||||
make O=/home/name/build/kernel menuconfig
|
make O=/home/name/build/kernel menuconfig
|
||||||
make O=/home/name/build/kernel
|
make O=/home/name/build/kernel
|
||||||
sudo make O=/home/name/build/kernel modules_install install
|
sudo make O=/home/name/build/kernel modules_install install
|
||||||
@ -227,8 +227,6 @@ Linux内核5.x版本 <http://kernel.org/>
|
|||||||
- 确保您至少有gcc 5.1可用。
|
- 确保您至少有gcc 5.1可用。
|
||||||
有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。
|
有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。
|
||||||
|
|
||||||
请注意,您仍然可以使用此内核运行a.out用户程序。
|
|
||||||
|
|
||||||
- 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile,
|
- 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile,
|
||||||
那么也可以进行 ``make install`` ,但是您可能需要先检查特定的lilo设置。
|
那么也可以进行 ``make install`` ,但是您可能需要先检查特定的lilo设置。
|
||||||
|
|
||||||
@ -282,67 +280,12 @@ Linux内核5.x版本 <http://kernel.org/>
|
|||||||
若遇到问题
|
若遇到问题
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
- 如果您发现了一些可能由于内核缺陷所导致的问题,请检查MAINTAINERS(维护者)
|
如果您发现了一些可能由于内核缺陷所导致的问题,请参阅:
|
||||||
文件看看是否有人与令您遇到麻烦的内核部分相关。如果无人在此列出,那么第二
|
Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 。
|
||||||
个最好的方案就是把它们发给我(torvalds@linux-foundation.org),也可能发送
|
|
||||||
到任何其他相关的邮件列表或新闻组。
|
|
||||||
|
|
||||||
- 在所有的缺陷报告中,【请】告诉我们您在说什么内核,如何复现问题,以及您的
|
想要理解内核错误报告,请参阅:
|
||||||
设置是什么的(使用您的常识)。如果问题是新的,请告诉我;如果问题是旧的,
|
Documentation/translations/zh_CN/admin-guide/bug-hunting.rst 。
|
||||||
请尝试告诉我您什么时候首次注意到它。
|
|
||||||
|
|
||||||
- 如果缺陷导致如下消息::
|
更多用GDB调试内核的信息,请参阅:
|
||||||
|
Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
|
||||||
unable to handle kernel paging request at address C0000010
|
和 Documentation/dev-tools/kgdb.rst 。
|
||||||
Oops: 0002
|
|
||||||
EIP: 0010:XXXXXXXX
|
|
||||||
eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx
|
|
||||||
esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx
|
|
||||||
ds: xxxx es: xxxx fs: xxxx gs: xxxx
|
|
||||||
Pid: xx, process nr: xx
|
|
||||||
xx xx xx xx xx xx xx xx xx xx
|
|
||||||
|
|
||||||
或者类似的内核调试信息显示在屏幕上或在系统日志里,请【如实】复制它。
|
|
||||||
可能对你来说转储(dump)看起来不可理解,但它确实包含可能有助于调试问题的
|
|
||||||
信息。转储上方的文本也很重要:它说明了内核转储代码的原因(在上面的示例中,
|
|
||||||
是由于内核指针错误)。更多关于如何理解转储的信息,请参见
|
|
||||||
Documentation/admin-guide/bug-hunting.rst。
|
|
||||||
|
|
||||||
- 如果使用 CONFIG_KALLSYMS 编译内核,则可以按原样发送转储,否则必须使用
|
|
||||||
``ksymoops`` 程序来理解转储(但通常首选使用CONFIG_KALLSYMS编译)。
|
|
||||||
此实用程序可从
|
|
||||||
https://www.kernel.org/pub/linux/utils/kernel/ksymoops/ 下载。
|
|
||||||
或者,您可以手动执行转储查找:
|
|
||||||
|
|
||||||
- 在调试像上面这样的转储时,如果您可以查找EIP值的含义,这将非常有帮助。
|
|
||||||
十六进制值本身对我或其他任何人都没有太大帮助:它会取决于特定的内核设置。
|
|
||||||
您应该做的是从EIP行获取十六进制值(忽略 ``0010:`` ),然后在内核名字列表
|
|
||||||
中查找它,以查看哪个内核函数包含有问题的地址。
|
|
||||||
|
|
||||||
要找到内核函数名,您需要找到与显示症状的内核相关联的系统二进制文件。就是
|
|
||||||
文件“linux/vmlinux”。要提取名字列表并将其与内核崩溃中的EIP进行匹配,
|
|
||||||
请执行::
|
|
||||||
|
|
||||||
nm vmlinux | sort | less
|
|
||||||
|
|
||||||
这将为您提供一个按升序排序的内核地址列表,从中很容易找到包含有问题的地址
|
|
||||||
的函数。请注意,内核调试消息提供的地址不一定与函数地址完全匹配(事实上,
|
|
||||||
这是不可能的),因此您不能只“grep”列表:不过列表将为您提供每个内核函数
|
|
||||||
的起点,因此通过查找起始地址低于你正在搜索的地址,但后一个函数的高于的
|
|
||||||
函数,你会找到您想要的。实际上,在您的问题报告中加入一些“上下文”可能是
|
|
||||||
一个好主意,给出相关的上下几行。
|
|
||||||
|
|
||||||
如果您由于某些原因无法完成上述操作(如您使用预编译的内核映像或类似的映像),
|
|
||||||
请尽可能多地告诉我您的相关设置信息,这会有所帮助。有关详细信息请阅读
|
|
||||||
‘Documentation/admin-guide/reporting-issues.rst’。
|
|
||||||
|
|
||||||
- 或者,您可以在正在运行的内核上使用gdb(只读的;即不能更改值或设置断点)。
|
|
||||||
为此,请首先使用-g编译内核;适当地编辑arch/x86/Makefile,然后执行 ``make
|
|
||||||
clean`` 。您还需要启用CONFIG_PROC_FS(通过 ``make config`` )。
|
|
||||||
|
|
||||||
使用新内核重新启动后,执行 ``gdb vmlinux /proc/kcore`` 。现在可以使用所有
|
|
||||||
普通的gdb命令。查找系统崩溃点的命令是 ``l *0xXXXXXXXX`` (将xxx替换为EIP
|
|
||||||
值)。
|
|
||||||
|
|
||||||
用gdb无法调试一个当前未运行的内核是由于gdb(错误地)忽略了编译内核的起始
|
|
||||||
偏移量。
|
|
||||||
|
293
Documentation/translations/zh_CN/admin-guide/bootconfig.rst
Normal file
293
Documentation/translations/zh_CN/admin-guide/bootconfig.rst
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/admin-guide/bootconfig.rst
|
||||||
|
|
||||||
|
:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
|
||||||
|
|
||||||
|
========
|
||||||
|
引导配置
|
||||||
|
========
|
||||||
|
|
||||||
|
:作者: Masami Hiramatsu <mhiramat@kernel.org>
|
||||||
|
|
||||||
|
概述
|
||||||
|
====
|
||||||
|
|
||||||
|
引导配置扩展了现有的内核命令行,以一种更有效率的方式在引导内核时进一步支持
|
||||||
|
键值数据。这允许管理员传递一份结构化关键字的配置文件。
|
||||||
|
|
||||||
|
配置文件语法
|
||||||
|
============
|
||||||
|
|
||||||
|
引导配置文件的语法采用非常简单的键值结构。每个关键字由点连接的单词组成,键
|
||||||
|
和值由 ``=`` 连接。值以分号( ``;`` )或换行符( ``\n`` )结尾。数组值中每
|
||||||
|
个元素由逗号( ``,`` )分隔。::
|
||||||
|
|
||||||
|
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
|
||||||
|
|
||||||
|
与内核命令行语法不同,逗号和 ``=`` 周围允许有空格。
|
||||||
|
|
||||||
|
关键字只允许包含字母、数字、连字符( ``-`` )和下划线( ``_`` )。值可包含
|
||||||
|
可打印字符和空格,但分号( ``;`` )、换行符( ``\n`` )、逗号( ``,`` )、
|
||||||
|
井号( ``#`` )和右大括号( ``}`` )等分隔符除外。
|
||||||
|
|
||||||
|
如果你需要在值中使用这些分隔符,可以用双引号( ``"VALUE"`` )或单引号
|
||||||
|
( ``'VALUE'`` )括起来。注意,引号无法转义。
|
||||||
|
|
||||||
|
键的值可以为空或不存在。这些键用于检查该键是否存在(类似布尔值)。
|
||||||
|
|
||||||
|
键值语法
|
||||||
|
--------
|
||||||
|
|
||||||
|
引导配置文件语法允许用户通过大括号合并键名部分相同的关键字。例如::
|
||||||
|
|
||||||
|
foo.bar.baz = value1
|
||||||
|
foo.bar.qux.quux = value2
|
||||||
|
|
||||||
|
也可以写成::
|
||||||
|
|
||||||
|
foo.bar {
|
||||||
|
baz = value1
|
||||||
|
qux.quux = value2
|
||||||
|
}
|
||||||
|
|
||||||
|
或者更紧凑一些,写成::
|
||||||
|
|
||||||
|
foo.bar { baz = value1; qux.quux = value2 }
|
||||||
|
|
||||||
|
在这两种样式中,引导解析时相同的关键字都会自动合并。因此可以追加类似的树或
|
||||||
|
键值。
|
||||||
|
|
||||||
|
相同关键字的值
|
||||||
|
--------------
|
||||||
|
|
||||||
|
禁止两个或多个值或数组共享同一个关键字。例如::
|
||||||
|
|
||||||
|
foo = bar, baz
|
||||||
|
foo = qux # !错误! 我们不可以重定义相同的关键字
|
||||||
|
|
||||||
|
如果你想要更新值,必须显式使用覆盖操作符 ``:=`` 。例如::
|
||||||
|
|
||||||
|
foo = bar, baz
|
||||||
|
foo := qux
|
||||||
|
|
||||||
|
这样 ``foo`` 关键字的值就变成了 ``qux`` 。这对于通过添加(部分)自定义引导
|
||||||
|
配置来覆盖默认值非常有用,免于解析默认引导配置。
|
||||||
|
|
||||||
|
如果你想对现有关键字追加值作为数组成员,可以使用 ``+=`` 操作符。例如::
|
||||||
|
|
||||||
|
foo = bar, baz
|
||||||
|
foo += qux
|
||||||
|
|
||||||
|
这样, ``foo`` 关键字就同时拥有了 ``bar`` , ``baz`` 和 ``qux`` 。
|
||||||
|
|
||||||
|
此外,父关键字下可同时存在值和子关键字。
|
||||||
|
例如,下列配置是可行的。::
|
||||||
|
|
||||||
|
foo = value1
|
||||||
|
foo.bar = value2
|
||||||
|
foo := value3 # 这会更新foo的值。
|
||||||
|
|
||||||
|
注意,裸值不能直接放进结构化关键字中,必须在大括号外定义它。例如::
|
||||||
|
|
||||||
|
foo {
|
||||||
|
bar = value1
|
||||||
|
bar {
|
||||||
|
baz = value2
|
||||||
|
qux = value3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
同时,关键字下值节点的顺序是固定的。如果值和子关键字同时存在,值永远是该关
|
||||||
|
键字的第一个子节点。因此如果用户先指定子关键字,如::
|
||||||
|
|
||||||
|
foo.bar = value1
|
||||||
|
foo = value2
|
||||||
|
|
||||||
|
则在程序(和/proc/bootconfig)中,它会按如下显示::
|
||||||
|
|
||||||
|
foo = value2
|
||||||
|
foo.bar = value1
|
||||||
|
|
||||||
|
注释
|
||||||
|
----
|
||||||
|
|
||||||
|
配置语法接受shell脚本风格的注释。注释以井号( ``#`` )开始,到换行符
|
||||||
|
( ``\n`` )结束。
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# comment line
|
||||||
|
foo = value # value is set to foo.
|
||||||
|
bar = 1, # 1st element
|
||||||
|
2, # 2nd element
|
||||||
|
3 # 3rd element
|
||||||
|
|
||||||
|
会被解析为::
|
||||||
|
|
||||||
|
foo = value
|
||||||
|
bar = 1, 2, 3
|
||||||
|
|
||||||
|
注意你不能把注释放在值和分隔符( ``,`` 或 ``;`` )之间。如下配置语法是错误的::
|
||||||
|
|
||||||
|
key = 1 # comment
|
||||||
|
,2
|
||||||
|
|
||||||
|
|
||||||
|
/proc/bootconfig
|
||||||
|
================
|
||||||
|
|
||||||
|
/proc/bootconfig是引导配置的用户空间接口。与/proc/cmdline不同,此文件内容以
|
||||||
|
键值列表样式显示。
|
||||||
|
每个键值对一行,样式如下::
|
||||||
|
|
||||||
|
KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
|
||||||
|
|
||||||
|
|
||||||
|
用引导配置引导内核
|
||||||
|
==================
|
||||||
|
|
||||||
|
用引导配置引导内核有两种方法:将引导配置附加到initrd镜像或直接嵌入内核中。
|
||||||
|
|
||||||
|
*initrd: initial RAM disk,初始内存磁盘*
|
||||||
|
|
||||||
|
将引导配置附加到initrd
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
由于默认情况下引导配置文件是用initrd加载的,因此它将被添加到initrd(initramfs)
|
||||||
|
镜像文件的末尾,其中包含填充、大小、校验值和12字节幻数,如下所示::
|
||||||
|
|
||||||
|
[initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
|
||||||
|
|
||||||
|
大小和校验值为小端序存放的32位无符号值。
|
||||||
|
|
||||||
|
当引导配置被加到initrd镜像时,整个文件大小会对齐到4字节。空字符( ``\0`` )
|
||||||
|
会填补对齐空隙。因此 ``size`` 就是引导配置文件的长度+填充的字节。
|
||||||
|
|
||||||
|
Linux内核在内存中解码initrd镜像的最后部分以获取引导配置数据。由于这种“背负式”
|
||||||
|
的方法,只要引导加载器传递了正确的initrd文件大小,就无需更改或更新引导加载器
|
||||||
|
和内核镜像本身。如果引导加载器意外传递了更长的大小,内核将无法找到引导配置数
|
||||||
|
据。
|
||||||
|
|
||||||
|
Linux内核在tools/bootconfig下提供了 ``bootconfig`` 命令来完成此操作,管理员
|
||||||
|
可以用它从initrd镜像中删除或追加配置文件。你可以用以下命令来构建它::
|
||||||
|
|
||||||
|
# make -C tools/bootconfig
|
||||||
|
|
||||||
|
要向initrd镜像添加你的引导配置文件,请按如下命令操作(旧数据会自动移除)::
|
||||||
|
|
||||||
|
# tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
|
||||||
|
|
||||||
|
要从镜像中移除配置,可以使用-d选项::
|
||||||
|
|
||||||
|
# tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
|
||||||
|
|
||||||
|
然后在内核命令行上添加 ``bootconfig`` 告诉内核去initrd文件末尾寻找内核配置。
|
||||||
|
|
||||||
|
将引导配置嵌入内核
|
||||||
|
------------------
|
||||||
|
|
||||||
|
如果你不能使用initrd,也可以通过Kconfig选项将引导配置文件嵌入内核中。在此情
|
||||||
|
况下,你需要用以下选项重新编译内核::
|
||||||
|
|
||||||
|
CONFIG_BOOT_CONFIG_EMBED=y
|
||||||
|
CONFIG_BOOT_CONFIG_EMBED_FILE="/引导配置/文件/的/路径"
|
||||||
|
|
||||||
|
``CONFIG_BOOT_CONFIG_EMBED_FILE`` 需要从源码树或对象树开始的引导配置文件的
|
||||||
|
绝对/相对路径。内核会将其嵌入作为默认引导配置。
|
||||||
|
|
||||||
|
与将引导配置附加到initrd一样,你也需要在内核命令行上添加 ``bootconfig`` 告诉
|
||||||
|
内核去启用内嵌的引导配置。
|
||||||
|
|
||||||
|
注意,即使你已经设置了此选项,仍可用附加到initrd的其他引导配置覆盖内嵌的引导
|
||||||
|
配置。
|
||||||
|
|
||||||
|
通过引导配置传递内核参数
|
||||||
|
========================
|
||||||
|
|
||||||
|
除了内核命令行,引导配置也可以用于传递内核参数。所有 ``kernel`` 关键字下的键
|
||||||
|
值对都将直接传递给内核命令行。此外, ``init`` 下的键值对将通过命令行传递给
|
||||||
|
init进程。参数按以下顺序与用户给定的内核命令行字符串相连,因此命令行参数可以
|
||||||
|
覆盖引导配置参数(这取决于子系统如何处理参数,但通常前面的参数将被后面的参数
|
||||||
|
覆盖)::
|
||||||
|
|
||||||
|
[bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
|
||||||
|
|
||||||
|
如果引导配置文件给出的kernel/init参数是::
|
||||||
|
|
||||||
|
kernel {
|
||||||
|
root = 01234567-89ab-cdef-0123-456789abcd
|
||||||
|
}
|
||||||
|
init {
|
||||||
|
splash
|
||||||
|
}
|
||||||
|
|
||||||
|
这将被复制到内核命令行字符串中,如下所示::
|
||||||
|
|
||||||
|
root="01234567-89ab-cdef-0123-456789abcd" -- splash
|
||||||
|
|
||||||
|
如果用户给出的其他命令行是::
|
||||||
|
|
||||||
|
ro bootconfig -- quiet
|
||||||
|
|
||||||
|
则最后的内核命令行如下::
|
||||||
|
|
||||||
|
root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
|
||||||
|
|
||||||
|
|
||||||
|
配置文件的限制
|
||||||
|
==============
|
||||||
|
|
||||||
|
当前最大的配置大小是32KB,关键字总数(不是键值条目)必须少于1024个节点。
|
||||||
|
注意:这不是条目数而是节点数,条目必须消耗超过2个节点(一个关键字和一个值)。
|
||||||
|
所以从理论上讲最多512个键值对。如果关键字平均包含3个单词,则可有256个键值对。
|
||||||
|
在大多数情况下,配置项的数量将少于100个条目,小于8KB,因此这应该足够了。如果
|
||||||
|
节点数超过1024,解析器将返回错误,即使文件大小小于32KB。(请注意,此最大尺寸
|
||||||
|
不包括填充的空字符。)
|
||||||
|
无论如何,因为 ``bootconfig`` 命令在附加启动配置到initrd映像时会验证它,用户
|
||||||
|
可以在引导之前注意到它。
|
||||||
|
|
||||||
|
|
||||||
|
引导配置API
|
||||||
|
===========
|
||||||
|
|
||||||
|
用户可以查询或遍历键值对,也可以查找(前缀)根关键字节点,并在查找该节点下的
|
||||||
|
键值。
|
||||||
|
|
||||||
|
如果您有一个关键字字符串,则可以直接使用 xbc_find_value() 查询该键的值。如果
|
||||||
|
你想知道引导配置里有哪些关键字,可以使用 xbc_for_each_key_value() 迭代键值对。
|
||||||
|
请注意,您需要使用 xbc_array_for_each_value() 访问数组的值,例如::
|
||||||
|
|
||||||
|
vnode = NULL;
|
||||||
|
xbc_find_value("key.word", &vnode);
|
||||||
|
if (vnode && xbc_node_is_array(vnode))
|
||||||
|
xbc_array_for_each_value(vnode, value) {
|
||||||
|
printk("%s ", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
如果您想查找具有前缀字符串的键,可以使用 xbc_find_node() 通过前缀字符串查找
|
||||||
|
节点,然后用 xbc_node_for_each_key_value() 迭代前缀节点下的键。
|
||||||
|
|
||||||
|
但最典型的用法是获取前缀下的命名值或前缀下的命名数组,例如::
|
||||||
|
|
||||||
|
root = xbc_find_node("key.prefix");
|
||||||
|
value = xbc_node_find_value(root, "option", &vnode);
|
||||||
|
...
|
||||||
|
xbc_node_for_each_array_value(root, "array-option", value, anode) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
这将访问值“key.prefix.option”的值和“key.prefix.array-option”的数组。
|
||||||
|
|
||||||
|
锁是不需要的,因为在初始化之后配置只读。如果需要修改,必须复制所有数据和关键字。
|
||||||
|
|
||||||
|
|
||||||
|
函数与结构体
|
||||||
|
============
|
||||||
|
|
||||||
|
相关定义的kernel-doc参见:
|
||||||
|
|
||||||
|
- include/linux/bootconfig.h
|
||||||
|
- lib/bootconfig.c
|
@ -63,6 +63,7 @@ Todolist:
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
bootconfig
|
||||||
clearing-warn-once
|
clearing-warn-once
|
||||||
cpu-load
|
cpu-load
|
||||||
cputopology
|
cputopology
|
||||||
@ -80,7 +81,6 @@ Todolist:
|
|||||||
* binderfs
|
* binderfs
|
||||||
* binfmt-misc
|
* binfmt-misc
|
||||||
* blockdev/index
|
* blockdev/index
|
||||||
* bootconfig
|
|
||||||
* braille-console
|
* braille-console
|
||||||
* btmrvl
|
* btmrvl
|
||||||
* cgroup-v1/index
|
* cgroup-v1/index
|
||||||
|
210
Documentation/translations/zh_CN/core-api/circular-buffers.rst
Normal file
210
Documentation/translations/zh_CN/core-api/circular-buffers.rst
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/core-api/circular-buffers.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
吴想成 Wu Xiangcheng <bobwxc@email.cn>
|
||||||
|
时奎亮 Alex Shi <alexs@kernel.org>
|
||||||
|
|
||||||
|
==========
|
||||||
|
环形缓冲区
|
||||||
|
==========
|
||||||
|
|
||||||
|
:作者: David Howells <dhowells@redhat.com>
|
||||||
|
:作者: Paul E. McKenney <paulmck@linux.ibm.com>
|
||||||
|
|
||||||
|
|
||||||
|
Linux 提供了许多可用于实现循环缓冲的特性。有两组这样的特性:
|
||||||
|
|
||||||
|
(1) 用于确定2次方大小的缓冲区信息的便利函数。
|
||||||
|
|
||||||
|
(2) 可以代替缓冲区中对象的生产者和消费者共享锁的内存屏障。
|
||||||
|
|
||||||
|
如下所述,要使用这些设施,只需要一个生产者和一个消费者。可以通过序列化来处理多个
|
||||||
|
生产者,并通过序列化来处理多个消费者。
|
||||||
|
|
||||||
|
.. Contents:
|
||||||
|
|
||||||
|
(*) 什么是环形缓冲区?
|
||||||
|
|
||||||
|
(*) 测量2次幂缓冲区
|
||||||
|
|
||||||
|
(*) 内存屏障与环形缓冲区的结合使用
|
||||||
|
- 生产者
|
||||||
|
- 消费者
|
||||||
|
|
||||||
|
(*) 延伸阅读
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
什么是环形缓冲区?
|
||||||
|
==================
|
||||||
|
|
||||||
|
首先,什么是环形缓冲区?环形缓冲区是具有固定的有限大小的缓冲区,它有两个索引:
|
||||||
|
|
||||||
|
(1) 'head'索引 - 生产者将元素插入缓冲区的位置。
|
||||||
|
|
||||||
|
(2) 'tail'索引 - 消费者在缓冲区中找到下一个元素的位置。
|
||||||
|
|
||||||
|
通常,当tail指针等于head指针时,表明缓冲区是空的;而当head指针比tail指针少一个时,
|
||||||
|
表明缓冲区是满的。
|
||||||
|
|
||||||
|
添加元素时,递增head索引;删除元素时,递增tail索引。tail索引不应该跳过head索引,
|
||||||
|
两个索引在到达缓冲区末端时都应该被赋值为0,从而允许海量的数据流过缓冲区。
|
||||||
|
|
||||||
|
通常情况下,元素都有相同的单元大小,但这并不是使用以下技术的严格要求。如果要在缓
|
||||||
|
冲区中包含多个元素或可变大小的元素,则索引可以增加超过1,前提是两个索引都没有超过
|
||||||
|
另一个。然而,实现者必须小心,因为超过一个单位大小的区域可能会覆盖缓冲区的末端并
|
||||||
|
且缓冲区会被分成两段。
|
||||||
|
|
||||||
|
测量2次幂缓冲区
|
||||||
|
===============
|
||||||
|
|
||||||
|
计算任意大小的环形缓冲区的占用或剩余容量通常是一个费时的操作,需要使用模(除法)
|
||||||
|
指令。但是如果缓冲区的大小为2次幂,则可以使用更快的按位与指令代替。
|
||||||
|
|
||||||
|
Linux提供了一组用于处理2次幂环形缓冲区的宏。可以通过以下方式使用::
|
||||||
|
|
||||||
|
#include <linux/circ_buf.h>
|
||||||
|
|
||||||
|
这些宏包括:
|
||||||
|
|
||||||
|
(#) 测量缓冲区的剩余容量::
|
||||||
|
|
||||||
|
CIRC_SPACE(head_index, tail_index, buffer_size);
|
||||||
|
|
||||||
|
返回缓冲区[1]中可插入元素的剩余空间大小。
|
||||||
|
|
||||||
|
|
||||||
|
(#) 测量缓冲区中的最大连续立即可用空间::
|
||||||
|
|
||||||
|
CIRC_SPACE_TO_END(head_index, tail_index, buffer_size);
|
||||||
|
|
||||||
|
返回缓冲区[1]中剩余的连续空间的大小,元素可以立即插入其中,而不必绕回到缓冲
|
||||||
|
区的开头。
|
||||||
|
|
||||||
|
|
||||||
|
(#) 测量缓冲区的使用数::
|
||||||
|
|
||||||
|
CIRC_CNT(head_index, tail_index, buffer_size);
|
||||||
|
|
||||||
|
返回当前占用缓冲区[2]的元素数量。
|
||||||
|
|
||||||
|
|
||||||
|
(#) 测量缓冲区的连续使用数::
|
||||||
|
|
||||||
|
CIRC_CNT_TO_END(head_index, tail_index, buffer_size);
|
||||||
|
|
||||||
|
返回可以从缓冲区中提取的连续元素[2]的数量,而不必绕回到缓冲区的开头。
|
||||||
|
|
||||||
|
这里的每一个宏名义上都会返回一个介于0和buffer_size-1之间的值,但是:
|
||||||
|
|
||||||
|
(1) CIRC_SPACE*()是为了在生产者中使用。对生产者来说,它们将返回一个下限,因为生
|
||||||
|
产者控制着head索引,但消费者可能仍然在另一个CPU上耗尽缓冲区并移动tail索引。
|
||||||
|
|
||||||
|
对消费者来说,它将显示一个上限,因为生产者可能正忙于耗尽空间。
|
||||||
|
|
||||||
|
(2) CIRC_CNT*()是为了在消费者中使用。对消费者来说,它们将返回一个下限,因为消费
|
||||||
|
者控制着tail索引,但生产者可能仍然在另一个CPU上填充缓冲区并移动head索引。
|
||||||
|
|
||||||
|
对于生产者,它将显示一个上限,因为消费者可能正忙于清空缓冲区。
|
||||||
|
|
||||||
|
(3) 对于第三方来说,生产者和消费者对索引的写入顺序是无法保证的,因为它们是独立的,
|
||||||
|
而且可能是在不同的CPU上进行的,所以在这种情况下的结果只是一种猜测,甚至可能
|
||||||
|
是错误的。
|
||||||
|
|
||||||
|
内存屏障与环形缓冲区的结合使用
|
||||||
|
==============================
|
||||||
|
|
||||||
|
通过将内存屏障与环形缓冲区结合使用,可以避免以下需求:
|
||||||
|
|
||||||
|
(1) 使用单个锁来控制对缓冲区两端的访问,从而允许同时填充和清空缓冲区;以及
|
||||||
|
|
||||||
|
(2) 使用原子计数器操作。
|
||||||
|
|
||||||
|
这有两个方面:填充缓冲区的生产者和清空缓冲区的消费者。在任何时候,只应有一个生产
|
||||||
|
者在填充缓冲区,同样的也只应有一个消费者在清空缓冲区,但双方可以同时操作。
|
||||||
|
|
||||||
|
|
||||||
|
生产者
|
||||||
|
------
|
||||||
|
|
||||||
|
生产者看起来像这样::
|
||||||
|
|
||||||
|
spin_lock(&producer_lock);
|
||||||
|
|
||||||
|
unsigned long head = buffer->head;
|
||||||
|
/* spin_unlock()和下一个spin_lock()提供必要的排序。 */
|
||||||
|
unsigned long tail = READ_ONCE(buffer->tail);
|
||||||
|
|
||||||
|
if (CIRC_SPACE(head, tail, buffer->size) >= 1) {
|
||||||
|
/* 添加一个元素到缓冲区 */
|
||||||
|
struct item *item = buffer[head];
|
||||||
|
|
||||||
|
produce_item(item);
|
||||||
|
|
||||||
|
smp_store_release(buffer->head,
|
||||||
|
(head + 1) & (buffer->size - 1));
|
||||||
|
|
||||||
|
/* wake_up()将确保在唤醒任何人之前提交head */
|
||||||
|
wake_up(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&producer_lock);
|
||||||
|
|
||||||
|
这将表明CPU必须在head索引使其对消费者可用之前写入新项目的内容,同时CPU必须在唤醒
|
||||||
|
消费者之前写入修改后的head索引。
|
||||||
|
|
||||||
|
请注意,wake_up()并不保证任何形式的屏障,除非确实唤醒了某些东西。因此我们不能依靠
|
||||||
|
它来进行排序。但是数组中始终有一个元素留空,因此生产者必须产生两个元素,然后才可
|
||||||
|
能破坏消费者当前正在读取的元素。同时,消费者连续调用之间成对的解锁-加锁提供了索引
|
||||||
|
读取(指示消费者已清空给定元素)和生产者对该相同元素的写入之间的必要顺序。
|
||||||
|
|
||||||
|
|
||||||
|
消费者
|
||||||
|
------
|
||||||
|
|
||||||
|
消费者看起来像这样::
|
||||||
|
|
||||||
|
spin_lock(&consumer_lock);
|
||||||
|
|
||||||
|
/* 读取该索引处的内容之前,先读取索引 */
|
||||||
|
unsigned long head = smp_load_acquire(buffer->head);
|
||||||
|
unsigned long tail = buffer->tail;
|
||||||
|
|
||||||
|
if (CIRC_CNT(head, tail, buffer->size) >= 1) {
|
||||||
|
|
||||||
|
/* 从缓冲区中提取一个元素 */
|
||||||
|
struct item *item = buffer[tail];
|
||||||
|
|
||||||
|
consume_item(item);
|
||||||
|
|
||||||
|
/* 在递增tail之前完成对描述符的读取。 */
|
||||||
|
smp_store_release(buffer->tail,
|
||||||
|
(tail + 1) & (buffer->size - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock(&consumer_lock);
|
||||||
|
|
||||||
|
这表明CPU在读取新元素之前确保索引是最新的,然后在写入新的尾指针之前应确保CPU已完
|
||||||
|
成读取该元素,这将擦除该元素。
|
||||||
|
|
||||||
|
请注意,使用READ_ONCE()和smp_load_acquire()来读取反向(head)索引。这可以防止编译
|
||||||
|
器丢弃并重新加载其缓存值。如果您能确定反向(head)索引将仅使用一次,则这不是必须
|
||||||
|
的。smp_load_acquire()还可以强制CPU对后续的内存引用进行排序。类似地,两种算法都使
|
||||||
|
用smp_store_release()来写入线程的索引。这记录了我们正在写入可以并发读取的内容的事
|
||||||
|
实,以防止编译器破坏存储,并强制对以前的访问进行排序。
|
||||||
|
|
||||||
|
|
||||||
|
延伸阅读
|
||||||
|
========
|
||||||
|
|
||||||
|
关于Linux的内存屏障设施的描述,请查看Documentation/memory-barriers.txt。
|
@ -0,0 +1,23 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/core-api/generic-radix-tree.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
|
||||||
|
|
||||||
|
===================
|
||||||
|
通用基数树/稀疏数组
|
||||||
|
===================
|
||||||
|
|
||||||
|
通用基数树/稀疏数组的相关内容请见include/linux/generic-radix-tree.h文件中的
|
||||||
|
“DOC: Generic radix trees/sparse arrays”。
|
||||||
|
|
||||||
|
通用基数树函数
|
||||||
|
--------------
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
include/linux/generic-radix-tree.h
|
80
Documentation/translations/zh_CN/core-api/idr.rst
Normal file
80
Documentation/translations/zh_CN/core-api/idr.rst
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/core-api/idr.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
吴想成 Wu Xiangcheng <bobwxc@email.cn>
|
||||||
|
时奎亮 Alex Shi <alexs@kernel.org>
|
||||||
|
|
||||||
|
======
|
||||||
|
ID分配
|
||||||
|
======
|
||||||
|
|
||||||
|
:作者: Matthew Wilcox
|
||||||
|
|
||||||
|
概述
|
||||||
|
====
|
||||||
|
|
||||||
|
要解决的一个常见问题是分配标识符(IDs);它通常是标识事物的数字。比如包括文件描述
|
||||||
|
符、进程ID、网络协议中的数据包标识符、SCSI标记和设备实例编号。IDR和IDA为这个问题
|
||||||
|
提供了一个合理的解决方案,以避免每个人都自创。IDR提供将ID映射到指针的能力,而IDA
|
||||||
|
仅提供ID分配,因此内存效率更高。
|
||||||
|
|
||||||
|
IDR接口已经被废弃,请使用 ``XArray`` 。
|
||||||
|
|
||||||
|
IDR的用法
|
||||||
|
=========
|
||||||
|
|
||||||
|
首先初始化一个IDR,对于静态分配的IDR使用DEFINE_IDR(),或者对于动态分配的IDR使用
|
||||||
|
idr_init()。
|
||||||
|
|
||||||
|
您可以调用idr_alloc()来分配一个未使用的ID。通过调用idr_find()查询与该ID相关的指针,
|
||||||
|
并通过调用idr_remove()释放该ID。
|
||||||
|
|
||||||
|
如果需要更改与一个ID相关联的指针,可以调用idr_replace()。这样做的一个常见原因是通
|
||||||
|
过将 ``NULL`` 指针传递给分配函数来保留ID;用保留的ID初始化对象,最后将初始化的对
|
||||||
|
象插入IDR。
|
||||||
|
|
||||||
|
一些用户需要分配大于 ``INT_MAX`` 的ID。到目前为止,所有这些用户都满足 ``UINT_MAX``
|
||||||
|
的限制,他们使用idr_alloc_u32()。如果您需要超出u32的ID,我们将与您合作以满足您的
|
||||||
|
需求。
|
||||||
|
|
||||||
|
如果需要按顺序分配ID,可以使用idr_alloc_cyclic()。处理较大数量的ID时,IDR的效率会
|
||||||
|
降低,所以使用这个函数会有一点代价。
|
||||||
|
|
||||||
|
要对IDR使用的所有指针进行操作,您可以使用基于回调的idr_for_each()或迭代器样式的
|
||||||
|
idr_for_each_entry()。您可能需要使用idr_for_each_entry_continue()来继续迭代。如果
|
||||||
|
迭代器不符合您的需求,您也可以使用idr_get_next()。
|
||||||
|
|
||||||
|
当使用完IDR后,您可以调用idr_destroy()来释放IDR占用的内存。这并不会释放IDR指向的
|
||||||
|
对象;如果您想这样做,请使用其中一个迭代器来执行此操作。
|
||||||
|
|
||||||
|
您可以使用idr_is_empty()来查看当前是否分配了任何ID。
|
||||||
|
|
||||||
|
如果在从IDR分配一个新ID时需要带锁,您可能需要传递一组限制性的GFP标志,但这可能导
|
||||||
|
致IDR无法分配内存。为了解决该问题,您可以在获取锁之前调用idr_preload(),然后在分
|
||||||
|
配之后调用idr_preload_end()。
|
||||||
|
|
||||||
|
IDR同步的相关内容请见include/linux/idr.h文件中的“DOC: idr sync”。
|
||||||
|
|
||||||
|
IDA的用法
|
||||||
|
=========
|
||||||
|
|
||||||
|
IDA的用法的相关内容请见lib/idr.c文件中的“DOC: IDA description”。
|
||||||
|
|
||||||
|
函数和数据结构
|
||||||
|
==============
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
include/linux/idr.h
|
||||||
|
|
||||||
|
lib/idr.c
|
@ -44,15 +44,15 @@
|
|||||||
assoc_array
|
assoc_array
|
||||||
xarray
|
xarray
|
||||||
rbtree
|
rbtree
|
||||||
|
idr
|
||||||
|
circular-buffers
|
||||||
|
generic-radix-tree
|
||||||
|
packing
|
||||||
|
|
||||||
Todolist:
|
Todolist:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
idr
|
|
||||||
circular-buffers
|
|
||||||
generic-radix-tree
|
|
||||||
packing
|
|
||||||
this_cpu_ops
|
this_cpu_ops
|
||||||
timekeeping
|
timekeeping
|
||||||
errseq
|
errseq
|
||||||
|
160
Documentation/translations/zh_CN/core-api/packing.rst
Normal file
160
Documentation/translations/zh_CN/core-api/packing.rst
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0+
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/core-api/packing.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
吴想成 Wu Xiangcheng <bobwxc@email.cn>
|
||||||
|
时奎亮 Alex Shi <alexs@kernel.org>
|
||||||
|
|
||||||
|
========================
|
||||||
|
通用的位域打包和解包函数
|
||||||
|
========================
|
||||||
|
|
||||||
|
问题陈述
|
||||||
|
--------
|
||||||
|
|
||||||
|
使用硬件时,必须在几种与其交互的方法之间进行选择。
|
||||||
|
|
||||||
|
可以将指针映射到在硬件设备的内存区上精心设计的结构体,并将其字段作为结构成员(可
|
||||||
|
能声明为位域)访问。但是由于CPU和硬件设备之间潜在的字节顺序不匹配,以这种方式编写
|
||||||
|
代码会降低其可移植性。
|
||||||
|
|
||||||
|
此外,必须密切注意将硬件文档中的寄存器定义转换为结构的位域索引。此外,一些硬件
|
||||||
|
(通常是网络设备)倾向于以违反任何合理字边界(有时甚至是64位)的方式对其寄存器字
|
||||||
|
段进行分组。这就造成了不得不在结构中定义寄存器字段的“高”和“低”部分的不便。
|
||||||
|
|
||||||
|
结构域定义的更可靠的替代方法是通过移动适当数量的位来提取所需的字段。但这仍然不能
|
||||||
|
防止字节顺序不匹配,除非所有内存访问都是逐字节执行的。此外,代码很容易变得杂乱无
|
||||||
|
章,同时可能会在所需的许多位移操作中丢失一些高层次的想法。
|
||||||
|
|
||||||
|
许多驱动程序采用了位移的方法,然后试图用定制的宏来减少杂乱无章的东西,但更多的时
|
||||||
|
候,这些宏所采用的捷径依旧妨碍了代码真正的可移植性。
|
||||||
|
|
||||||
|
解决方案
|
||||||
|
--------
|
||||||
|
|
||||||
|
该API涉及2个基本操作:
|
||||||
|
|
||||||
|
- 将一个CPU可使用的数字打包到内存缓冲区中(具有硬件约束/特殊性)。
|
||||||
|
- 将内存缓冲区(具有硬件约束/特殊性)解压缩为一个CPU可使用的数字。
|
||||||
|
|
||||||
|
该API提供了对所述硬件约束和特殊性以及CPU字节序的抽象,因此这两者之间可能不匹配。
|
||||||
|
|
||||||
|
这些API函数的基本单元是u64。从CPU的角度来看,位63总是意味着字节7的位偏移量7,尽管
|
||||||
|
只是逻辑上的。问题是:我们将这个比特放在内存的什么位置?
|
||||||
|
|
||||||
|
以下示例介绍了打包u64字段的内存布局。打包缓冲区中的字节偏移量始终默认为0,1...7。
|
||||||
|
示例显示的是逻辑字节和位所在的位置。
|
||||||
|
|
||||||
|
1. 通常情况下(无特殊性),我们会这样做:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
|
||||||
|
7 6 5 4
|
||||||
|
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||||
|
3 2 1 0
|
||||||
|
|
||||||
|
也就是说,CPU可使用的u64的MSByte(7)位于内存偏移量0处,而u64的LSByte(0)位于内存偏移量7处。
|
||||||
|
|
||||||
|
这对应于大多数人认为的“大端”,其中位i对应于数字2^i。这在代码注释中也称为“逻辑”符号。
|
||||||
|
|
||||||
|
|
||||||
|
2. 如果设置了QUIRK_MSB_ON_THE_RIGHT,我们按如下方式操作:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
|
||||||
|
7 6 5 4
|
||||||
|
24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
|
||||||
|
3 2 1 0
|
||||||
|
|
||||||
|
也就是说,QUIRK_MSB_ON_THE_RIGHT不会影响字节定位,但会反转字节内的位偏移量。
|
||||||
|
|
||||||
|
|
||||||
|
3. 如果设置了QUIRK_LITTLE_ENDIAN,我们按如下方式操作:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
|
||||||
|
4 5 6 7
|
||||||
|
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
|
||||||
|
0 1 2 3
|
||||||
|
|
||||||
|
因此,QUIRK_LITTLE_ENDIAN意味着在内存区域内,每个4字节的字的每个字节都被放置在与
|
||||||
|
该字的边界相比的镜像位置。
|
||||||
|
|
||||||
|
|
||||||
|
4. 如果设置了QUIRK_MSB_ON_THE_RIGHT和QUIRK_LITTLE_ENDIAN,我们这样做:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
|
4 5 6 7
|
||||||
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
|
0 1 2 3
|
||||||
|
|
||||||
|
|
||||||
|
5. 如果只设置了QUIRK_LSW32_IS_FIRST,我们这样做:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||||
|
3 2 1 0
|
||||||
|
63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
|
||||||
|
7 6 5 4
|
||||||
|
|
||||||
|
在这种情况下,8字节内存区域解释如下:前4字节对应最不重要的4字节的字,后4字节对应
|
||||||
|
更重要的4字节的字。
|
||||||
|
|
||||||
|
6. 如果设置了QUIRK_LSW32_IS_FIRST和QUIRK_MSB_ON_THE_RIGHT,我们这样做:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 8 9 10 11 12 13 14 15 0 1 2 3 4 5 6 7
|
||||||
|
3 2 1 0
|
||||||
|
56 57 58 59 60 61 62 63 48 49 50 51 52 53 54 55 40 41 42 43 44 45 46 47 32 33 34 35 36 37 38 39
|
||||||
|
7 6 5 4
|
||||||
|
|
||||||
|
|
||||||
|
7. 如果设置了QUIRK_LSW32_IS_FIRST和QUIRK_LITTLE_ENDIAN,则如下所示:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24
|
||||||
|
0 1 2 3
|
||||||
|
39 38 37 36 35 34 33 32 47 46 45 44 43 42 41 40 55 54 53 52 51 50 49 48 63 62 61 60 59 58 57 56
|
||||||
|
4 5 6 7
|
||||||
|
|
||||||
|
|
||||||
|
8. 如果设置了QUIRK_LSW32_IS_FIRST,QUIRK_LITTLE_ENDIAN和QUIRK_MSB_ON_THE_RIGHT,
|
||||||
|
则如下所示:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
|
0 1 2 3
|
||||||
|
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
|
4 5 6 7
|
||||||
|
|
||||||
|
|
||||||
|
我们总是认为我们的偏移量好像没有特殊性,然后在访问内存区域之前翻译它们。
|
||||||
|
|
||||||
|
预期用途
|
||||||
|
--------
|
||||||
|
|
||||||
|
选择使用该API的驱动程序首先需要确定上述3种quirk组合(共8种)中的哪一种与硬件文档
|
||||||
|
中描述的相匹配。然后,他们应该封装packing()函数,创建一个新的xxx_packing(),使用
|
||||||
|
适当的QUIRK_* one-hot 位集合来调用它。
|
||||||
|
|
||||||
|
packing()函数返回一个int类型的错误码,以防止程序员使用不正确的API。这些错误预计不
|
||||||
|
会在运行时发生,因此xxx_packing()返回void并简单地接受这些错误是合理的。它可以选择
|
||||||
|
转储栈或打印错误描述。
|
37
Documentation/translations/zh_CN/devicetree/changesets.rst
Normal file
37
Documentation/translations/zh_CN/devicetree/changesets.rst
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/Devicetree/changesets.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
|
||||||
|
============
|
||||||
|
设备树变更集
|
||||||
|
============
|
||||||
|
|
||||||
|
设备树变更集是一种方法,它允许人们以这样一种方式在实时树中使用变化,即要么使用全部的
|
||||||
|
变化,要么不使用。如果在使用变更集的过程中发生错误,那么树将被回滚到之前的状态。一个
|
||||||
|
变更集也可以在使用后被删除。
|
||||||
|
|
||||||
|
当一个变更集被使用时,所有的改变在发出OF_RECONFIG通知器之前被一次性使用到树上。这是
|
||||||
|
为了让接收者在收到通知时看到一个完整的、一致的树的状态。
|
||||||
|
|
||||||
|
一个变化集的顺序如下。
|
||||||
|
|
||||||
|
1. of_changeset_init() - 初始化一个变更集。
|
||||||
|
|
||||||
|
2. 一些DT树变化的调用,of_changeset_attach_node(), of_changeset_detach_node(),
|
||||||
|
of_changeset_add_property(), of_changeset_remove_property,
|
||||||
|
of_changeset_update_property()来准备一组变更。此时不会对活动树做任何变更。所有
|
||||||
|
的变更操作都记录在of_changeset的 `entries` 列表中。
|
||||||
|
|
||||||
|
3. of_changeset_apply() - 将变更使用到树上。要么整个变更集被使用,要么如果有错误,
|
||||||
|
树会被恢复到之前的状态。核心通过锁确保正确的顺序。如果需要的话,可以使用一个解锁的
|
||||||
|
__of_changeset_apply版本。
|
||||||
|
|
||||||
|
如果一个成功使用的变更集需要被删除,可以用of_changeset_revert()来完成。
|
@ -0,0 +1,31 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/Devicetree/dynamic-resolution-notes.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
========================
|
||||||
|
Devicetree动态解析器说明
|
||||||
|
========================
|
||||||
|
|
||||||
|
本文描述了内核内DeviceTree解析器的实现,它位于drivers/of/resolver.c中。
|
||||||
|
|
||||||
|
解析器如何工作?
|
||||||
|
----------------
|
||||||
|
|
||||||
|
解析器被赋予一个任意的树作为输入,该树用适当的dtc选项编译,并有一个/plugin/标签。这就产
|
||||||
|
生了适当的__fixups__和__local_fixups__节点。
|
||||||
|
|
||||||
|
解析器依次通过以下步骤工作:
|
||||||
|
|
||||||
|
1. 从实时树中获取最大的设备树phandle值 + 1.
|
||||||
|
2. 调整树的所有本地 phandles,以解决这个量。
|
||||||
|
3. 使用 __local__fixups__ 节点信息以相同的量调整所有本地引用。
|
||||||
|
4. 对于__fixups__节点中的每个属性,找到它在实时树中引用的节点。这是用来标记该节点的标签。
|
||||||
|
5. 检索fixup的目标的phandle。
|
||||||
|
6. 对于属性中的每个fixup,找到节点:属性:偏移的位置,并用phandle值替换它。
|
@ -24,21 +24,16 @@ Open Firmware 和 Devicetree
|
|||||||
|
|
||||||
usage-model
|
usage-model
|
||||||
of_unittest
|
of_unittest
|
||||||
|
kernel-api
|
||||||
Todolist:
|
|
||||||
|
|
||||||
* kernel-api
|
|
||||||
|
|
||||||
Devicetree Overlays
|
Devicetree Overlays
|
||||||
===================
|
===================
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
Todolist:
|
changesets
|
||||||
|
dynamic-resolution-notes
|
||||||
* changesets
|
overlay-notes
|
||||||
* dynamic-resolution-notes
|
|
||||||
* overlay-notes
|
|
||||||
|
|
||||||
Devicetree Bindings
|
Devicetree Bindings
|
||||||
===================
|
===================
|
||||||
|
58
Documentation/translations/zh_CN/devicetree/kernel-api.rst
Normal file
58
Documentation/translations/zh_CN/devicetree/kernel-api.rst
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/Devicetree/kernel-api.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
|
||||||
|
=================
|
||||||
|
内核中的设备树API
|
||||||
|
=================
|
||||||
|
|
||||||
|
核心函数
|
||||||
|
--------
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/of/base.c
|
||||||
|
|
||||||
|
include/linux/of.h
|
||||||
|
|
||||||
|
drivers/of/property.c
|
||||||
|
|
||||||
|
include/linux/of_graph.h
|
||||||
|
|
||||||
|
drivers/of/address.c
|
||||||
|
|
||||||
|
drivers/of/irq.c
|
||||||
|
|
||||||
|
drivers/of/fdt.c
|
||||||
|
|
||||||
|
驱动模型函数
|
||||||
|
------------
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
include/linux/of_device.h
|
||||||
|
|
||||||
|
drivers/of/device.c
|
||||||
|
|
||||||
|
include/linux/of_platform.h
|
||||||
|
|
||||||
|
drivers/of/platform.c
|
||||||
|
|
||||||
|
覆盖和动态DT函数
|
||||||
|
----------------
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/of/resolver.c
|
||||||
|
|
||||||
|
drivers/of/dynamic.c
|
||||||
|
|
||||||
|
drivers/of/overlay.c
|
140
Documentation/translations/zh_CN/devicetree/overlay-notes.rst
Normal file
140
Documentation/translations/zh_CN/devicetree/overlay-notes.rst
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/Devicetree/overlay-notes.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
==============
|
||||||
|
设备树覆盖说明
|
||||||
|
==============
|
||||||
|
|
||||||
|
本文档描述了drivers/of/overlay.c中的内核内设备树覆盖功能的实现,是
|
||||||
|
Documentation/devicetree/dynamic-resolution-notes.rst[1]的配套文档。
|
||||||
|
|
||||||
|
覆盖如何工作
|
||||||
|
------------
|
||||||
|
|
||||||
|
设备树覆盖的目的是修改内核的实时树,并使修改以反映变化的方式影响内核的状态。
|
||||||
|
由于内核主要处理的是设备,任何新的设备节点如果导致一个活动的设备,就应该创建它,
|
||||||
|
而如果设备节点被禁用或被全部删除,受影响的设备应该被取消注册。
|
||||||
|
|
||||||
|
让我们举个例子,我们有一个foo板,它的基本树形图如下::
|
||||||
|
|
||||||
|
---- foo.dts ---------------------------------------------------------------
|
||||||
|
/* FOO平台 */
|
||||||
|
/dts-v1/;
|
||||||
|
/ {
|
||||||
|
compatible = "corp,foo";
|
||||||
|
|
||||||
|
/* 共享的资源 */
|
||||||
|
res: res {
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 芯片上的外围设备 */
|
||||||
|
ocp: ocp {
|
||||||
|
/* 总是被实例化的外围设备 */
|
||||||
|
peripheral1 { ... };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- foo.dts ---------------------------------------------------------------
|
||||||
|
|
||||||
|
覆盖bar.dts,
|
||||||
|
::
|
||||||
|
|
||||||
|
---- bar.dts - 按标签覆盖目标位置 ----------------------------
|
||||||
|
/dts-v1/;
|
||||||
|
/插件/;
|
||||||
|
&ocp {
|
||||||
|
/* bar外围 */
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* 各种属性和子节点 */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- bar.dts ---------------------------------------------------------------
|
||||||
|
|
||||||
|
当加载(并按照[1]中描述的方式解决)时,应该产生foo+bar.dts::
|
||||||
|
|
||||||
|
---- foo+bar.dts -----------------------------------------------------------
|
||||||
|
/* FOO平台 + bar外围 */
|
||||||
|
/ {
|
||||||
|
compatible = "corp,foo";
|
||||||
|
|
||||||
|
/* 共享资源 */
|
||||||
|
res: res {
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 芯片上的外围设备 */
|
||||||
|
ocp: ocp {
|
||||||
|
/* 总是被实例化的外围设备 */
|
||||||
|
peripheral1 { ... };
|
||||||
|
|
||||||
|
/* bar外围 */
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* 各种属性和子节点 */
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
---- foo+bar.dts -----------------------------------------------------------
|
||||||
|
|
||||||
|
作为覆盖的结果,已经创建了一个新的设备节点(bar),因此将注册一个bar平台设备,
|
||||||
|
如果加载了匹配的设备驱动程序,将按预期创建设备。
|
||||||
|
|
||||||
|
如果基础DT不是用-@选项编译的,那么“&ocp”标签将不能用于将覆盖节点解析到基础
|
||||||
|
DT中的适当位置。在这种情况下,可以提供目标路径。通过标签的目标位置的语法是比
|
||||||
|
较好的,因为不管标签在DT中出现在哪里,覆盖都可以被应用到任何包含标签的基础DT上。
|
||||||
|
|
||||||
|
上面的bar.dts例子被修改为使用目标路径语法,即为::
|
||||||
|
|
||||||
|
---- bar.dts - 通过明确的路径覆盖目标位置 --------------------
|
||||||
|
/dts-v1/;
|
||||||
|
/插件/;
|
||||||
|
&{/ocp} {
|
||||||
|
/* bar外围 */
|
||||||
|
bar {
|
||||||
|
compatible = "corp,bar";
|
||||||
|
... /* 各种外围设备和子节点 */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
---- bar.dts ---------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
内核中关于覆盖的API
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
该API相当容易使用。
|
||||||
|
|
||||||
|
1) 调用of_overlay_fdt_apply()来创建和应用一个覆盖的变更集。返回值是一个
|
||||||
|
错误或一个识别这个覆盖的cookie。
|
||||||
|
|
||||||
|
2) 调用of_overlay_remove()来删除和清理先前通过调用of_overlay_fdt_apply()
|
||||||
|
而创建的覆盖变更集。不允许删除一个被另一个覆盖的覆盖变化集。
|
||||||
|
|
||||||
|
最后,如果你需要一次性删除所有的覆盖,只需调用of_overlay_remove_all(),
|
||||||
|
它将以正确的顺序删除每一个覆盖。
|
||||||
|
|
||||||
|
你可以选择注册在覆盖操作中被调用的通知器。详见
|
||||||
|
of_overlay_notifier_register/unregister和enum of_overlay_notify_action。
|
||||||
|
|
||||||
|
OF_OVERLAY_PRE_APPLY、OF_OVERLAY_POST_APPLY或OF_OVERLAY_PRE_REMOVE
|
||||||
|
的通知器回调可以存储指向覆盖层中的设备树节点或其内容的指针,但这些指针不能持
|
||||||
|
续到OF_OVERLAY_POST_REMOVE的通知器回调。在OF_OVERLAY_POST_REMOVE通
|
||||||
|
知器被调用后,包含覆盖层的内存将被kfree()ed。请注意,即使OF_OVERLAY_POST_REMOVE
|
||||||
|
的通知器返回错误,内存也会被kfree()ed。
|
||||||
|
|
||||||
|
drivers/of/dynamic.c中的变更集通知器是第二种类型的通知器,可以通过应用或移除
|
||||||
|
覆盖层来触发。这些通知器不允许在覆盖层或其内容中存储指向设备树节点的指针。当包含
|
||||||
|
覆盖层的内存因移除覆盖层而被释放时,覆盖层代码并不能防止这类指针仍然有效。
|
||||||
|
|
||||||
|
任何其他保留指向覆盖层节点或数据的指针的代码都被认为是一个错误,因为在移除覆盖层
|
||||||
|
后,该指针将指向已释放的内存。
|
||||||
|
|
||||||
|
覆盖层的用户必须特别注意系统上发生的整体操作,以确保其他内核代码不保留任何指向覆
|
||||||
|
盖层节点或数据的指针。任何无意中使用这种指针的例子是,如果一个驱动或子系统模块在
|
||||||
|
应用了覆盖后被加载,并且该驱动或子系统扫描了整个设备树或其大部分,包括覆盖节点。
|
69
Documentation/translations/zh_CN/driver-api/gpio/index.rst
Normal file
69
Documentation/translations/zh_CN/driver-api/gpio/index.rst
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
.. include:: ../../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/driver-api/gpio/index.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
=======================
|
||||||
|
通用型输入/输出(GPIO)
|
||||||
|
=======================
|
||||||
|
|
||||||
|
目录:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
legacy
|
||||||
|
|
||||||
|
Todolist:
|
||||||
|
|
||||||
|
* intro
|
||||||
|
* using-gpio
|
||||||
|
* driver
|
||||||
|
* consumer
|
||||||
|
* board
|
||||||
|
* drivers-on-gpio
|
||||||
|
* bt8xxgpio
|
||||||
|
|
||||||
|
核心
|
||||||
|
====
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
include/linux/gpio/driver.h
|
||||||
|
|
||||||
|
drivers/gpio/gpiolib.c
|
||||||
|
|
||||||
|
ACPI支持
|
||||||
|
========
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/gpio/gpiolib-acpi.c
|
||||||
|
|
||||||
|
设备树支持
|
||||||
|
==========
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/gpio/gpiolib-of.c
|
||||||
|
|
||||||
|
设备管理支持
|
||||||
|
============
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/gpio/gpiolib-devres.c
|
||||||
|
|
||||||
|
sysfs帮助(函数)
|
||||||
|
=================
|
||||||
|
|
||||||
|
该API在以下内核代码中:
|
||||||
|
|
||||||
|
drivers/gpio/gpiolib-sysfs.c
|
@ -1,39 +1,28 @@
|
|||||||
Chinese translated version of Documentation/admin-guide/gpio
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
If you have any comment or update to the content, please contact the
|
.. include:: ../../disclaimer-zh_CN.rst
|
||||||
original document maintainer directly. However, if you have a problem
|
|
||||||
communicating in English you can also ask the Chinese maintainer for
|
|
||||||
help. Contact the Chinese maintainer if this translation is outdated
|
|
||||||
or if there is a problem with the translation.
|
|
||||||
|
|
||||||
Maintainer: Grant Likely <grant.likely@secretlab.ca>
|
:Original: Documentation/driver-api/gpio/legacy.rst
|
||||||
Linus Walleij <linus.walleij@linaro.org>
|
|
||||||
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
Documentation/admin-guide/gpio 的中文翻译
|
|
||||||
|
|
||||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
:翻译:
|
||||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
|
||||||
译存在问题,请联系中文版维护者。
|
傅炜 Fu Wei <tekkamanninja@gmail.com>
|
||||||
英文版维护者: Grant Likely <grant.likely@secretlab.ca>
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
Linus Walleij <linus.walleij@linaro.org>
|
|
||||||
中文版维护者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
:校译:
|
||||||
中文版翻译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
中文版校译者: 傅炜 Fu Wei <tekkamanninja@gmail.com>
|
|
||||||
|
|
||||||
|
|
||||||
以下为正文
|
传统GPIO接口
|
||||||
---------------------------------------------------------------------
|
============
|
||||||
GPIO 接口
|
|
||||||
|
|
||||||
本文档提供了一个在Linux下访问GPIO的公约概述。
|
本文档概述了Linux下的GPIO访问公约。
|
||||||
|
|
||||||
这些函数以 gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的
|
这些函数以 gpio_* 作为前缀。其他的函数不允许使用这样的前缀或相关的
|
||||||
__gpio_* 前缀。
|
__gpio_* 前缀。
|
||||||
|
|
||||||
|
|
||||||
什么是GPIO?
|
什么是GPIO?
|
||||||
==========
|
============
|
||||||
"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可
|
"通用输入/输出口"(GPIO)是一个灵活的由软件控制的数字信号。他们可
|
||||||
由多种芯片提供,且对于从事嵌入式和定制硬件的 Linux 开发者来说是
|
由多种芯片提供,且对于从事嵌入式和定制硬件的 Linux 开发者来说是
|
||||||
比较熟悉。每个GPIO 都代表一个连接到特定引脚或球栅阵列(BGA)封装中
|
比较熟悉。每个GPIO 都代表一个连接到特定引脚或球栅阵列(BGA)封装中
|
||||||
@ -99,6 +88,7 @@ GPIO 公约
|
|||||||
|
|
||||||
标识 GPIO
|
标识 GPIO
|
||||||
---------
|
---------
|
||||||
|
|
||||||
GPIO 是通过无符号整型来标识的,范围是 0 到 MAX_INT。保留“负”数
|
GPIO 是通过无符号整型来标识的,范围是 0 到 MAX_INT。保留“负”数
|
||||||
用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层
|
用于其他目的,例如标识信号“在这个板子上不可用”或指示错误。未接触底层
|
||||||
硬件的代码会忽略这些整数。
|
硬件的代码会忽略这些整数。
|
||||||
@ -115,7 +105,7 @@ FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中
|
|||||||
|
|
||||||
如果你要初始化一个带有无效 GPIO 编号的结构体,可以使用一些负编码
|
如果你要初始化一个带有无效 GPIO 编号的结构体,可以使用一些负编码
|
||||||
(如"-EINVAL"),那将使其永远不会是有效。来测试这样一个结构体中的编号
|
(如"-EINVAL"),那将使其永远不会是有效。来测试这样一个结构体中的编号
|
||||||
是否关联一个 GPIO,你可使用以下断言:
|
是否关联一个 GPIO,你可使用以下断言::
|
||||||
|
|
||||||
int gpio_is_valid(int number);
|
int gpio_is_valid(int number);
|
||||||
|
|
||||||
@ -128,11 +118,12 @@ FPGA 的特定板子上使用 80-95。编号不一定要连续,那些平台中
|
|||||||
|
|
||||||
使用 GPIO
|
使用 GPIO
|
||||||
---------
|
---------
|
||||||
|
|
||||||
对于一个 GPIO,系统应该做的第一件事情就是通过 gpio_request()
|
对于一个 GPIO,系统应该做的第一件事情就是通过 gpio_request()
|
||||||
函数分配它,见下文。
|
函数分配它,见下文。
|
||||||
|
|
||||||
接下来是设置I/O方向,这通常是在板级启动代码中为所使用的 GPIO 设置
|
接下来是设置I/O方向,这通常是在板级启动代码中为所使用的 GPIO 设置
|
||||||
platform_device 时完成。
|
platform_device 时完成::
|
||||||
|
|
||||||
/* 设置为输入或输出, 返回 0 或负的错误代码 */
|
/* 设置为输入或输出, 返回 0 或负的错误代码 */
|
||||||
int gpio_direction_input(unsigned gpio);
|
int gpio_direction_input(unsigned gpio);
|
||||||
@ -157,12 +148,13 @@ get/set(获取/设置)函数调用没法返回错误,且有可能是配置错误
|
|||||||
|
|
||||||
|
|
||||||
访问自旋锁安全的 GPIO
|
访问自旋锁安全的 GPIO
|
||||||
-------------------
|
---------------------
|
||||||
|
|
||||||
大多数 GPIO 控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以
|
大多数 GPIO 控制器可以通过内存读/写指令来访问。这些指令不会休眠,可以
|
||||||
安全地在硬(非线程)中断例程和类似的上下文中完成。
|
安全地在硬(非线程)中断例程和类似的上下文中完成。
|
||||||
|
|
||||||
对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(见下文),使用
|
对于那些用 gpio_cansleep()测试总是返回失败的 GPIO(见下文),使用
|
||||||
以下的函数访问:
|
以下的函数访问::
|
||||||
|
|
||||||
/* GPIO 输入:返回零或非零 */
|
/* GPIO 输入:返回零或非零 */
|
||||||
int gpio_get_value(unsigned gpio);
|
int gpio_get_value(unsigned gpio);
|
||||||
@ -188,17 +180,18 @@ GPIO值是布尔值,零表示低电平,非零表示高电平。当读取一
|
|||||||
|
|
||||||
|
|
||||||
访问可能休眠的 GPIO
|
访问可能休眠的 GPIO
|
||||||
-----------------
|
-------------------
|
||||||
|
|
||||||
某些 GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消息访问。读或写这些
|
某些 GPIO 控制器必须通过基于总线(如 I2C 或 SPI)的消息访问。读或写这些
|
||||||
GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要
|
GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其反馈。期间需要
|
||||||
休眠,这不能在 IRQ 例程(中断上下文)中执行。
|
休眠,这不能在 IRQ 例程(中断上下文)中执行。
|
||||||
|
|
||||||
支持此类 GPIO 的平台通过以下函数返回非零值来区分出这种 GPIO。(此函数需要
|
支持此类 GPIO 的平台通过以下函数返回非零值来区分出这种 GPIO。(此函数需要
|
||||||
一个之前通过 gpio_request 分配到的有效 GPIO 编号):
|
一个之前通过 gpio_request 分配到的有效 GPIO 编号)::
|
||||||
|
|
||||||
int gpio_cansleep(unsigned gpio);
|
int gpio_cansleep(unsigned gpio);
|
||||||
|
|
||||||
为了访问这种 GPIO,内核定义了一套不同的函数:
|
为了访问这种 GPIO,内核定义了一套不同的函数::
|
||||||
|
|
||||||
/* GPIO 输入:返回零或非零 ,可能会休眠 */
|
/* GPIO 输入:返回零或非零 ,可能会休眠 */
|
||||||
int gpio_get_value_cansleep(unsigned gpio);
|
int gpio_get_value_cansleep(unsigned gpio);
|
||||||
@ -214,25 +207,26 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
|
|||||||
事实,这些处理例程实际上和自旋锁安全的函数是一样的。
|
事实,这些处理例程实际上和自旋锁安全的函数是一样的。
|
||||||
|
|
||||||
** 除此之外 ** 调用设置和配置此类 GPIO 的函数也必须在允许休眠的上下文中,
|
** 除此之外 ** 调用设置和配置此类 GPIO 的函数也必须在允许休眠的上下文中,
|
||||||
因为它们可能也需要访问 GPIO 控制器芯片: (这些设置函数通常在板级启动代码或者
|
因为它们可能也需要访问 GPIO 控制器芯片 (这些设置函数通常在板级启动代码或者
|
||||||
驱动探测/断开代码中,所以这是一个容易满足的约束条件。)
|
驱动探测/断开代码中,所以这是一个容易满足的约束条件。) ::
|
||||||
|
|
||||||
gpio_direction_input()
|
gpio_direction_input()
|
||||||
gpio_direction_output()
|
gpio_direction_output()
|
||||||
gpio_request()
|
gpio_request()
|
||||||
|
|
||||||
## gpio_request_one()
|
## gpio_request_one()
|
||||||
## gpio_request_array()
|
## gpio_request_array()
|
||||||
## gpio_free_array()
|
## gpio_free_array()
|
||||||
|
|
||||||
gpio_free()
|
gpio_free()
|
||||||
gpio_set_debounce()
|
gpio_set_debounce()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
声明和释放 GPIO
|
声明和释放 GPIO
|
||||||
----------------------------
|
----------------
|
||||||
为了有助于捕获系统配置错误,定义了两个函数。
|
|
||||||
|
为了有助于捕获系统配置错误,定义了两个函数::
|
||||||
|
|
||||||
/* 申请 GPIO, 返回 0 或负的错误代码.
|
/* 申请 GPIO, 返回 0 或负的错误代码.
|
||||||
* 非空标签可能有助于诊断.
|
* 非空标签可能有助于诊断.
|
||||||
@ -256,9 +250,9 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
|
|||||||
某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和
|
某些平台可能也使用 GPIO 作为电源管理激活信号(例如通过关闭未使用芯片区和
|
||||||
简单地关闭未使用时钟)。
|
简单地关闭未使用时钟)。
|
||||||
|
|
||||||
对于 GPIO 使用 pinctrl 子系统已知的引脚,子系统应该被告知其使用情况;
|
对于 GPIO 使用引脚控制子系统已知的引脚,子系统应该被告知其使用情况;
|
||||||
一个 gpiolib 驱动的 .request()操作应调用 pinctrl_gpio_request(),
|
一个 gpiolib 驱动的 .request()操作应调用 pinctrl_gpio_request(),
|
||||||
而 gpiolib 驱动的 .free()操作应调用 pinctrl_gpio_free()。pinctrl
|
而 gpiolib 驱动的 .free()操作应调用 pinctrl_gpio_free()。引脚控制
|
||||||
子系统允许 pinctrl_gpio_request()在某个引脚或引脚组以复用形式“属于”
|
子系统允许 pinctrl_gpio_request()在某个引脚或引脚组以复用形式“属于”
|
||||||
一个设备时都成功返回。
|
一个设备时都成功返回。
|
||||||
|
|
||||||
@ -270,7 +264,7 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其
|
|||||||
|
|
||||||
某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的
|
某些平台允许部分或所有 GPIO 信号使用不同的引脚。类似的,GPIO 或引脚的
|
||||||
其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用
|
其他方面也需要配置,如上拉/下拉。平台软件应该在对这些 GPIO 调用
|
||||||
gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映射表,
|
gpio_request()前将这类细节配置好,例如使用引脚控制子系统的映射表,
|
||||||
使得 GPIO 的用户无须关注这些细节。
|
使得 GPIO 的用户无须关注这些细节。
|
||||||
|
|
||||||
还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。
|
还有一个值得注意的是在释放 GPIO 前,你必须停止使用它。
|
||||||
@ -278,7 +272,7 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
|
|||||||
|
|
||||||
注意:申请一个 GPIO 并没有以任何方式配置它,只不过标识那个 GPIO 处于使用
|
注意:申请一个 GPIO 并没有以任何方式配置它,只不过标识那个 GPIO 处于使用
|
||||||
状态。必须有另外的代码来处理引脚配置(如控制 GPIO 使用的引脚、上拉/下拉)。
|
状态。必须有另外的代码来处理引脚配置(如控制 GPIO 使用的引脚、上拉/下拉)。
|
||||||
考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数:
|
考虑到大多数情况下声明 GPIO 之后就会立即配置它们,所以定义了以下三个辅助函数::
|
||||||
|
|
||||||
/* 申请一个 GPIO 信号, 同时通过特定的'flags'初始化配置,
|
/* 申请一个 GPIO 信号, 同时通过特定的'flags'初始化配置,
|
||||||
* 其他和 gpio_request()的参数和返回值相同
|
* 其他和 gpio_request()的参数和返回值相同
|
||||||
@ -326,7 +320,7 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
|
|||||||
将来这些标志可能扩展到支持更多的属性。
|
将来这些标志可能扩展到支持更多的属性。
|
||||||
|
|
||||||
更进一步,为了更简单地声明/释放多个 GPIO,'struct gpio'被引进来封装所有
|
更进一步,为了更简单地声明/释放多个 GPIO,'struct gpio'被引进来封装所有
|
||||||
这三个领域:
|
这三个领域::
|
||||||
|
|
||||||
struct gpio {
|
struct gpio {
|
||||||
unsigned gpio;
|
unsigned gpio;
|
||||||
@ -334,7 +328,7 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
|
|||||||
const char *label;
|
const char *label;
|
||||||
};
|
};
|
||||||
|
|
||||||
一个典型的用例:
|
一个典型的用例::
|
||||||
|
|
||||||
static struct gpio leds_gpios[] = {
|
static struct gpio leds_gpios[] = {
|
||||||
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默认开启 */
|
{ 32, GPIOF_OUT_INIT_HIGH, "Power LED" }, /* 默认开启 */
|
||||||
@ -356,9 +350,10 @@ gpio_request()前将这类细节配置好,例如使用 pinctrl 子系统的映
|
|||||||
|
|
||||||
|
|
||||||
GPIO 映射到 IRQ
|
GPIO 映射到 IRQ
|
||||||
--------------------
|
----------------
|
||||||
|
|
||||||
GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上不同的命名空间
|
GPIO 编号是无符号整数;IRQ 编号也是。这些构成了两个逻辑上不同的命名空间
|
||||||
(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射:
|
(GPIO 0 不一定使用 IRQ 0)。你可以通过以下函数在它们之间实现映射::
|
||||||
|
|
||||||
/* 映射 GPIO 编号到 IRQ 编号 */
|
/* 映射 GPIO 编号到 IRQ 编号 */
|
||||||
int gpio_to_irq(unsigned gpio);
|
int gpio_to_irq(unsigned gpio);
|
||||||
@ -384,7 +379,8 @@ irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所
|
|||||||
|
|
||||||
|
|
||||||
模拟开漏信号
|
模拟开漏信号
|
||||||
----------------------------
|
------------
|
||||||
|
|
||||||
有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平
|
有时在只有低电平信号作为实际驱动结果(译者注:多个输出连接于一点,逻辑电平
|
||||||
结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语
|
结果为所有输出的逻辑与)的时候,共享的信号线需要使用“开漏”信号。(该术语
|
||||||
适用于 CMOS 管;而 TTL 用“集电极开路”。)一个上拉电阻使信号为高电平。这
|
适用于 CMOS 管;而 TTL 用“集电极开路”。)一个上拉电阻使信号为高电平。这
|
||||||
@ -408,9 +404,44 @@ irq_to_gpio()返回的非错误值大多数通常可以被 gpio_get_value()所
|
|||||||
这不一定是错误的。一个常见的例子就是 I2C 时钟的延长:一个需要较慢时钟的
|
这不一定是错误的。一个常见的例子就是 I2C 时钟的延长:一个需要较慢时钟的
|
||||||
从设备延迟 SCK 的上升沿,而 I2C 主设备相应地调整其信号传输速率。
|
从设备延迟 SCK 的上升沿,而 I2C 主设备相应地调整其信号传输速率。
|
||||||
|
|
||||||
|
GPIO控制器和引脚控制子系统
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
SOC上的GPIO控制器可能与引脚控制子系统紧密结合,即引脚可以与可选的gpio功
|
||||||
|
能一起被其他功能使用。我们已经涵盖了这样的情况,例如一个GPIO控制器需要保
|
||||||
|
留一个引脚或通过调用以下任何一个引脚来设置其方向::
|
||||||
|
|
||||||
|
pinctrl_gpio_request()
|
||||||
|
pinctrl_gpio_free()
|
||||||
|
pinctrl_gpio_direction_input()
|
||||||
|
pinctrl_gpio_direction_output()
|
||||||
|
|
||||||
|
但是,引脚控制子系统是如何将GPIO号码(这是一个全局事项)与某个引脚控制器
|
||||||
|
上的某个引脚交叉关联的?
|
||||||
|
|
||||||
|
这是通过注册引脚的“范围”来实现的,这基本上是交叉参考表。这些描述是在
|
||||||
|
Documentation/driver-api/pin-control.rst
|
||||||
|
|
||||||
|
虽然引脚分配完全由引脚控制子系统管理,但gpio(在gpiolib下)仍由gpio驱动
|
||||||
|
维护。可能发生的情况是,SoC中的不同引脚范围由不同的gpio驱动器管理。
|
||||||
|
|
||||||
|
这使得在调用 "pinctrl_gpio_request" 之前,让gpio驱动向pin ctrl子系
|
||||||
|
统宣布它们的引脚范围是合理的,以便在使用任何gpio之前要求引脚控制子系统准
|
||||||
|
备相应的引脚。
|
||||||
|
|
||||||
|
为此,gpio控制器可以用引脚控制子系统注册其引脚范围。目前有两种方法:有或
|
||||||
|
无DT。
|
||||||
|
|
||||||
|
关于对DT的支持,请参考 Documentation/devicetree/bindings/gpio/gpio.txt.
|
||||||
|
|
||||||
|
对于非DT支持,用户可以用适当的参数调用gpiochip_add_pin_range(),将一
|
||||||
|
系列的gpio引脚注册到引脚控制驱动上。为此,必须将引脚控制设备的名称字符串
|
||||||
|
作为参数之一传给这个程序。
|
||||||
|
|
||||||
|
|
||||||
|
这些公约忽略了什么?
|
||||||
|
====================
|
||||||
|
|
||||||
这些公约忽略了什么?
|
|
||||||
================
|
|
||||||
这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且
|
这些公约忽略的最大一件事就是引脚复用,因为这属于高度芯片特定的属性且
|
||||||
没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚
|
没有可移植性。某个平台可能不需要明确的复用信息;有的对于任意给定的引脚
|
||||||
可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将
|
可能只有两个功能选项;有的可能每个引脚有八个功能选项;有的可能可以将
|
||||||
@ -433,8 +464,9 @@ Linux 的系统。)
|
|||||||
当前,动态定义 GPIO 并不是标准的,例如作为配置一个带有某些 GPIO 扩展器的
|
当前,动态定义 GPIO 并不是标准的,例如作为配置一个带有某些 GPIO 扩展器的
|
||||||
附加电路板的副作用。
|
附加电路板的副作用。
|
||||||
|
|
||||||
GPIO 实现者的框架 (可选)
|
GPIO 实现者的框架(可选)
|
||||||
=====================
|
=========================
|
||||||
|
|
||||||
前面提到了,有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持
|
前面提到了,有一个可选的实现框架,让平台使用相同的编程接口,更加简单地支持
|
||||||
不同种类的 GPIO 控制器。这个框架称为"gpiolib"。
|
不同种类的 GPIO 控制器。这个框架称为"gpiolib"。
|
||||||
|
|
||||||
@ -444,15 +476,16 @@ GPIO 实现者的框架 (可选)
|
|||||||
|
|
||||||
|
|
||||||
控制器驱动: gpio_chip
|
控制器驱动: gpio_chip
|
||||||
-------------------
|
---------------------
|
||||||
|
|
||||||
在框架中每个 GPIO 控制器都包装为一个 "struct gpio_chip",他包含了
|
在框架中每个 GPIO 控制器都包装为一个 "struct gpio_chip",他包含了
|
||||||
该类型的每个控制器的常用信息:
|
该类型的每个控制器的常用信息:
|
||||||
|
|
||||||
- 设置 GPIO 方向的方法
|
- 设置 GPIO 方向的方法
|
||||||
- 用于访问 GPIO 值的方法
|
- 用于访问 GPIO 值的方法
|
||||||
- 告知调用其方法是否可能休眠的标志
|
- 告知调用其方法是否可能休眠的标志
|
||||||
- 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态)
|
- 可选的 debugfs 信息导出方法 (显示类似上拉配置一样的额外状态)
|
||||||
- 诊断标签
|
- 诊断标签
|
||||||
|
|
||||||
也包含了来自 device.platform_data 的每个实例的数据:它第一个 GPIO 的
|
也包含了来自 device.platform_data 的每个实例的数据:它第一个 GPIO 的
|
||||||
编号和它可用的 GPIO 的数量。
|
编号和它可用的 GPIO 的数量。
|
||||||
@ -471,7 +504,8 @@ GPIO 实现者的框架 (可选)
|
|||||||
|
|
||||||
|
|
||||||
平台支持
|
平台支持
|
||||||
-------
|
--------
|
||||||
|
|
||||||
为了支持这个框架,一个平台的 Kconfig 文件将会 "select"(选择)
|
为了支持这个框架,一个平台的 Kconfig 文件将会 "select"(选择)
|
||||||
ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的
|
ARCH_REQUIRE_GPIOLIB 或 ARCH_WANT_OPTIONAL_GPIOLIB,并让它的
|
||||||
<asm/gpio.h> 包含 <asm-generic/gpio.h>,同时定义三个方法:
|
<asm/gpio.h> 包含 <asm-generic/gpio.h>,同时定义三个方法:
|
||||||
@ -489,7 +523,7 @@ ARCH_WANT_OPTIONAL_GPIOLIB 意味着 gpiolib 核心默认关闭,且用户可以
|
|||||||
如果这些选项都没被选择,该平台就不通过 GPIO-lib 支持 GPIO,且代码不可以
|
如果这些选项都没被选择,该平台就不通过 GPIO-lib 支持 GPIO,且代码不可以
|
||||||
被用户使能。
|
被用户使能。
|
||||||
|
|
||||||
以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度:
|
以下这些方法的实现可以直接使用框架代码,并总是通过 gpio_chip 调度::
|
||||||
|
|
||||||
#define gpio_get_value __gpio_get_value
|
#define gpio_get_value __gpio_get_value
|
||||||
#define gpio_set_value __gpio_set_value
|
#define gpio_set_value __gpio_set_value
|
||||||
@ -508,7 +542,8 @@ arch_initcall()或者更早的地方集成进平台初始化代码,使这些 G
|
|||||||
且他们通常可以作为 IRQ 使用。
|
且他们通常可以作为 IRQ 使用。
|
||||||
|
|
||||||
板级支持
|
板级支持
|
||||||
-------
|
--------
|
||||||
|
|
||||||
对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器、专用芯片、多功能器件、FPGA
|
对于外部 GPIO 控制器(例如 I2C 或 SPI 扩展器、专用芯片、多功能器件、FPGA
|
||||||
或 CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道
|
或 CPLD),大多数常用板级特定代码都可以注册控制器设备,并保证他们的驱动知道
|
||||||
gpiochip_add()所使用的 GPIO 编号。他们的起始编号通常跟在平台特定的 GPIO
|
gpiochip_add()所使用的 GPIO 编号。他们的起始编号通常跟在平台特定的 GPIO
|
||||||
@ -526,8 +561,9 @@ GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是
|
|||||||
设备变成无效时移除它们。
|
设备变成无效时移除它们。
|
||||||
|
|
||||||
|
|
||||||
用户空间的 Sysfs 接口(可选)
|
用户空间的 Sysfs 接口(可选)
|
||||||
========================
|
=============================
|
||||||
|
|
||||||
使用“gpiolib”实现框架的平台可以选择配置一个 GPIO 的 sysfs 用户接口。
|
使用“gpiolib”实现框架的平台可以选择配置一个 GPIO 的 sysfs 用户接口。
|
||||||
这不同于 debugfs 接口,因为它提供的是对 GPIO方向和值的控制,而不只显示
|
这不同于 debugfs 接口,因为它提供的是对 GPIO方向和值的控制,而不只显示
|
||||||
一个GPIO 的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。
|
一个GPIO 的状态摘要。此外,它可以出现在没有调试支持的产品级系统中。
|
||||||
@ -548,6 +584,7 @@ GPIO 可以工作之后才可被注册。解决这类依赖的的一种方法是
|
|||||||
|
|
||||||
Sysfs 中的路径
|
Sysfs 中的路径
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
在/sys/class/gpio 中有 3 类入口:
|
在/sys/class/gpio 中有 3 类入口:
|
||||||
|
|
||||||
- 用于在用户空间控制 GPIO 的控制接口;
|
- 用于在用户空间控制 GPIO 的控制接口;
|
||||||
@ -625,8 +662,9 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
|||||||
|
|
||||||
|
|
||||||
从内核代码中导出
|
从内核代码中导出
|
||||||
-------------
|
----------------
|
||||||
内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出:
|
|
||||||
|
内核代码可以明确地管理那些已通过 gpio_request()申请的 GPIO 的导出::
|
||||||
|
|
||||||
/* 导出 GPIO 到用户空间 */
|
/* 导出 GPIO 到用户空间 */
|
||||||
int gpio_export(unsigned gpio, bool direction_may_change);
|
int gpio_export(unsigned gpio, bool direction_may_change);
|
||||||
@ -648,3 +686,9 @@ GPIO 控制器的路径类似 /sys/class/gpio/gpiochip42/ (对于从#42 GPIO
|
|||||||
在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
|
在 GPIO 被导出之后,gpio_export_link()允许在 sysfs 文件系统的任何地方
|
||||||
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
|
创建一个到这个 GPIO sysfs 节点的符号链接。这样驱动就可以通过一个描述性的
|
||||||
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
|
名字,在 sysfs 中他们所拥有的设备下提供一个(到这个 GPIO sysfs 节点的)接口。
|
||||||
|
|
||||||
|
|
||||||
|
API参考
|
||||||
|
=======
|
||||||
|
|
||||||
|
本节中列出的函数已被废弃。在新的代码中应该使用基于GPIO描述符的API。
|
132
Documentation/translations/zh_CN/driver-api/index.rst
Normal file
132
Documentation/translations/zh_CN/driver-api/index.rst
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/driver-api/index.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
========================
|
||||||
|
Linux驱动实现者的API指南
|
||||||
|
========================
|
||||||
|
|
||||||
|
内核提供了各种各样的接口来支持设备驱动的开发。这份文档只是对其中一些接口进行了
|
||||||
|
一定程度的整理——希望随着时间的推移,它能变得更好!可用的小节可以在下面看到。
|
||||||
|
|
||||||
|
.. class:: toc-title
|
||||||
|
|
||||||
|
目录列表:
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
gpio/index
|
||||||
|
io_ordering
|
||||||
|
|
||||||
|
Todolist:
|
||||||
|
|
||||||
|
* driver-model/index
|
||||||
|
* basics
|
||||||
|
* infrastructure
|
||||||
|
* ioctl
|
||||||
|
* early-userspace/index
|
||||||
|
* pm/index
|
||||||
|
* clk
|
||||||
|
* device-io
|
||||||
|
* dma-buf
|
||||||
|
* device_link
|
||||||
|
* component
|
||||||
|
* message-based
|
||||||
|
* infiniband
|
||||||
|
* aperture
|
||||||
|
* frame-buffer
|
||||||
|
* regulator
|
||||||
|
* reset
|
||||||
|
* iio/index
|
||||||
|
* input
|
||||||
|
* usb/index
|
||||||
|
* firewire
|
||||||
|
* pci/index
|
||||||
|
* cxl/index
|
||||||
|
* spi
|
||||||
|
* i2c
|
||||||
|
* ipmb
|
||||||
|
* ipmi
|
||||||
|
* i3c/index
|
||||||
|
* interconnect
|
||||||
|
* devfreq
|
||||||
|
* hsi
|
||||||
|
* edac
|
||||||
|
* scsi
|
||||||
|
* libata
|
||||||
|
* target
|
||||||
|
* mailbox
|
||||||
|
* mtdnand
|
||||||
|
* miscellaneous
|
||||||
|
* mei/index
|
||||||
|
* mtd/index
|
||||||
|
* mmc/index
|
||||||
|
* nvdimm/index
|
||||||
|
* w1
|
||||||
|
* rapidio/index
|
||||||
|
* s390-drivers
|
||||||
|
* vme
|
||||||
|
* 80211/index
|
||||||
|
* uio-howto
|
||||||
|
* firmware/index
|
||||||
|
* pin-control
|
||||||
|
* md/index
|
||||||
|
* media/index
|
||||||
|
* misc_devices
|
||||||
|
* nfc/index
|
||||||
|
* dmaengine/index
|
||||||
|
* slimbus
|
||||||
|
* soundwire/index
|
||||||
|
* thermal/index
|
||||||
|
* fpga/index
|
||||||
|
* acpi/index
|
||||||
|
* auxiliary_bus
|
||||||
|
* backlight/lp855x-driver.rst
|
||||||
|
* connector
|
||||||
|
* console
|
||||||
|
* dcdbas
|
||||||
|
* eisa
|
||||||
|
* isa
|
||||||
|
* isapnp
|
||||||
|
* io-mapping
|
||||||
|
* generic-counter
|
||||||
|
* memory-devices/index
|
||||||
|
* men-chameleon-bus
|
||||||
|
* ntb
|
||||||
|
* nvmem
|
||||||
|
* parport-lowlevel
|
||||||
|
* pps
|
||||||
|
* ptp
|
||||||
|
* phy/index
|
||||||
|
* pwm
|
||||||
|
* pldmfw/index
|
||||||
|
* rfkill
|
||||||
|
* serial/index
|
||||||
|
* sm501
|
||||||
|
* surface_aggregator/index
|
||||||
|
* switchtec
|
||||||
|
* sync_file
|
||||||
|
* tty/index
|
||||||
|
* vfio-mediated-device
|
||||||
|
* vfio
|
||||||
|
* vfio-pci-device-specific-driver-acceptance
|
||||||
|
* xilinx/index
|
||||||
|
* xillybus
|
||||||
|
* zorro
|
||||||
|
* hte/index
|
||||||
|
|
||||||
|
.. only:: subproject and html
|
||||||
|
|
||||||
|
Indices
|
||||||
|
=======
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
60
Documentation/translations/zh_CN/driver-api/io_ordering.rst
Normal file
60
Documentation/translations/zh_CN/driver-api/io_ordering.rst
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
.. SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
|
:Original: Documentation/driver-api/io_ordering.rst
|
||||||
|
|
||||||
|
:翻译:
|
||||||
|
|
||||||
|
林永听 Lin Yongting <linyongting@gmail.com>
|
||||||
|
司延腾 Yanteng Si <siyanteng@loongson.cn>
|
||||||
|
|
||||||
|
:校译:
|
||||||
|
|
||||||
|
===========================
|
||||||
|
对内存映射地址的I/O写入排序
|
||||||
|
===========================
|
||||||
|
|
||||||
|
在某些平台上,所谓的内存映射I/O是弱顺序。在这些平台上,驱动开发者有责任
|
||||||
|
保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全”
|
||||||
|
设备寄存器或桥寄存器,触发IO芯片清刷未处理的写操作到达设备后才处理读操作,
|
||||||
|
而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。
|
||||||
|
这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存
|
||||||
|
屏障操作,mb(),不过仅适用于I/O)。
|
||||||
|
|
||||||
|
假设一个设备驱动程的具体例子::
|
||||||
|
|
||||||
|
...
|
||||||
|
CPU A: spin_lock_irqsave(&dev_lock, flags)
|
||||||
|
CPU A: val = readl(my_status);
|
||||||
|
CPU A: ...
|
||||||
|
CPU A: writel(newval, ring_ptr);
|
||||||
|
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
||||||
|
...
|
||||||
|
CPU B: spin_lock_irqsave(&dev_lock, flags)
|
||||||
|
CPU B: val = readl(my_status);
|
||||||
|
CPU B: ...
|
||||||
|
CPU B: writel(newval2, ring_ptr);
|
||||||
|
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
||||||
|
...
|
||||||
|
|
||||||
|
上述例子中,设备可能会先接收到newval2的值,然后接收到newval的值,问题就
|
||||||
|
发生了。不过很容易通过下面方法来修复::
|
||||||
|
|
||||||
|
...
|
||||||
|
CPU A: spin_lock_irqsave(&dev_lock, flags)
|
||||||
|
CPU A: val = readl(my_status);
|
||||||
|
CPU A: ...
|
||||||
|
CPU A: writel(newval, ring_ptr);
|
||||||
|
CPU A: (void)readl(safe_register); /* 配置寄存器?*/
|
||||||
|
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
||||||
|
...
|
||||||
|
CPU B: spin_lock_irqsave(&dev_lock, flags)
|
||||||
|
CPU B: val = readl(my_status);
|
||||||
|
CPU B: ...
|
||||||
|
CPU B: writel(newval2, ring_ptr);
|
||||||
|
CPU B: (void)readl(safe_register); /* 配置寄存器?*/
|
||||||
|
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
||||||
|
|
||||||
|
在解决方案中,读取safe_register寄存器,触发IO芯片清刷未处理的写操作,
|
||||||
|
再处理后面的读操作,防止引发数据不一致问题。
|
@ -108,6 +108,7 @@ TODOList:
|
|||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
core-api/index
|
core-api/index
|
||||||
|
driver-api/index
|
||||||
locking/index
|
locking/index
|
||||||
accounting/index
|
accounting/index
|
||||||
cpu-freq/index
|
cpu-freq/index
|
||||||
@ -120,10 +121,10 @@ TODOList:
|
|||||||
scheduler/index
|
scheduler/index
|
||||||
mm/index
|
mm/index
|
||||||
peci/index
|
peci/index
|
||||||
|
PCI/index
|
||||||
|
|
||||||
TODOList:
|
TODOList:
|
||||||
|
|
||||||
* driver-api/index
|
|
||||||
* block/index
|
* block/index
|
||||||
* cdrom/index
|
* cdrom/index
|
||||||
* ide/index
|
* ide/index
|
||||||
@ -148,7 +149,6 @@ TODOList:
|
|||||||
* crypto/index
|
* crypto/index
|
||||||
* bpf/index
|
* bpf/index
|
||||||
* usb/index
|
* usb/index
|
||||||
* PCI/index
|
|
||||||
* scsi/index
|
* scsi/index
|
||||||
* misc-devices/index
|
* misc-devices/index
|
||||||
* mhi/index
|
* mhi/index
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
Chinese translated version of Documentation/driver-api/io_ordering.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: Lin Yongting <linyongting@gmail.com>
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
Documentation/driver-api/io_ordering.rst 的中文翻译
|
|
||||||
|
|
||||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
|
||||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
|
||||||
译存在问题,请联系中文版维护者。
|
|
||||||
|
|
||||||
中文版维护者: 林永听 Lin Yongting <linyongting@gmail.com>
|
|
||||||
中文版翻译者: 林永听 Lin Yongting <linyongting@gmail.com>
|
|
||||||
中文版校译者: 林永听 Lin Yongting <linyongting@gmail.com>
|
|
||||||
|
|
||||||
|
|
||||||
以下为正文
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
|
|
||||||
在某些平台上,所谓的内存映射I/O是弱顺序。在这些平台上,驱动开发者有责任
|
|
||||||
保证I/O内存映射地址的写操作按程序图意的顺序达到设备。通常读取一个“安全”
|
|
||||||
设备寄存器或桥寄存器,触发IO芯片清刷未处理的写操作到达设备后才处理读操作,
|
|
||||||
而达到保证目的。驱动程序通常在spinlock保护的临界区退出之前使用这种技术。
|
|
||||||
这也可以保证后面的写操作只在前面的写操作之后到达设备(这非常类似于内存
|
|
||||||
屏障操作,mb(),不过仅适用于I/O)。
|
|
||||||
|
|
||||||
假设一个设备驱动程的具体例子:
|
|
||||||
|
|
||||||
...
|
|
||||||
CPU A: spin_lock_irqsave(&dev_lock, flags)
|
|
||||||
CPU A: val = readl(my_status);
|
|
||||||
CPU A: ...
|
|
||||||
CPU A: writel(newval, ring_ptr);
|
|
||||||
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
|
||||||
...
|
|
||||||
CPU B: spin_lock_irqsave(&dev_lock, flags)
|
|
||||||
CPU B: val = readl(my_status);
|
|
||||||
CPU B: ...
|
|
||||||
CPU B: writel(newval2, ring_ptr);
|
|
||||||
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
|
||||||
...
|
|
||||||
|
|
||||||
上述例子中,设备可能会先接收到newval2的值,然后接收到newval的值,问题就
|
|
||||||
发生了。不过很容易通过下面方法来修复:
|
|
||||||
|
|
||||||
...
|
|
||||||
CPU A: spin_lock_irqsave(&dev_lock, flags)
|
|
||||||
CPU A: val = readl(my_status);
|
|
||||||
CPU A: ...
|
|
||||||
CPU A: writel(newval, ring_ptr);
|
|
||||||
CPU A: (void)readl(safe_register); /* 配置寄存器?*/
|
|
||||||
CPU A: spin_unlock_irqrestore(&dev_lock, flags)
|
|
||||||
...
|
|
||||||
CPU B: spin_lock_irqsave(&dev_lock, flags)
|
|
||||||
CPU B: val = readl(my_status);
|
|
||||||
CPU B: ...
|
|
||||||
CPU B: writel(newval2, ring_ptr);
|
|
||||||
CPU B: (void)readl(safe_register); /* 配置寄存器?*/
|
|
||||||
CPU B: spin_unlock_irqrestore(&dev_lock, flags)
|
|
||||||
|
|
||||||
在解决方案中,读取safe_register寄存器,触发IO芯片清刷未处理的写操作,
|
|
||||||
再处理后面的读操作,防止引发数据不一致问题。
|
|
@ -1,212 +0,0 @@
|
|||||||
Chinese translated version of Documentation/admin-guide/bug-hunting.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: Dave Young <hidave.darkstar@gmail.com>
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
Documentation/admin-guide/bug-hunting.rst 的中文翻译
|
|
||||||
|
|
||||||
如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
|
|
||||||
交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
|
|
||||||
译存在问题,请联系中文版维护者。
|
|
||||||
|
|
||||||
中文版维护者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
|
|
||||||
中文版翻译者: 杨瑞 Dave Young <hidave.darkstar@gmail.com>
|
|
||||||
中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
|
|
||||||
王聪 Wang Cong <xiyou.wangcong@gmail.com>
|
|
||||||
|
|
||||||
以下为正文
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
|
|
||||||
注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg,等等)。
|
|
||||||
忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
|
|
||||||
ksymoops的来自2.6的Oops,人们只会让你重贴一次。
|
|
||||||
|
|
||||||
快速总结
|
|
||||||
-------------
|
|
||||||
|
|
||||||
发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
|
|
||||||
和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
|
|
||||||
价值。
|
|
||||||
|
|
||||||
如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
|
|
||||||
尽可能地稳定。
|
|
||||||
|
|
||||||
Oops在哪里?
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
通常Oops文本由klogd从内核缓冲区里读取并传给syslogd,由syslogd写到syslog文件中,
|
|
||||||
典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
|
|
||||||
能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
|
|
||||||
cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
|
|
||||||
果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-
|
|
||||||
|
|
||||||
(1) 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
|
|
||||||
这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
|
|
||||||
息滚动到了终端的上面,你会发现以高分辩率启动(比如,vga=791)会让你读到更多的文
|
|
||||||
本。(注意:这需要vesafb,所以对‘早期’的oops没有帮助)
|
|
||||||
|
|
||||||
(2)用串口终端启动(请参看Documentation/admin-guide/serial-console.rst),运行一个null
|
|
||||||
modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。
|
|
||||||
|
|
||||||
(3)使用Kdump(请参看Documentation/admin-guide/kdump/kdump.rst),
|
|
||||||
使用在Documentation/admin-guide/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
|
|
||||||
环形缓冲区。
|
|
||||||
|
|
||||||
完整信息
|
|
||||||
----------------
|
|
||||||
|
|
||||||
注意:以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
|
|
||||||
一些信息仍然适用。 特别注意的是,请忽略任何ksymoops的引用。
|
|
||||||
|
|
||||||
From: Linus Torvalds <torvalds@osdl.org>
|
|
||||||
|
|
||||||
怎样跟踪Oops.. [原发到linux-kernel的一封邮件]
|
|
||||||
|
|
||||||
主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)
|
|
||||||
|
|
||||||
实际上,你有办法使它更简单。我有两个不同的方法:
|
|
||||||
|
|
||||||
gdb /usr/src/linux/vmlinux
|
|
||||||
gdb> disassemble <offending_function>
|
|
||||||
|
|
||||||
那是发现问题的简单办法,至少如果bug报告做的好的情况下(象这个一样-运行ksymoops
|
|
||||||
得到oops发生的函数及函数内的偏移)。
|
|
||||||
|
|
||||||
哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。
|
|
||||||
|
|
||||||
另一件要做的事是反汇编bug报告的“Code”部分:ksymoops也会用正确的工具来做这件事,
|
|
||||||
但如果没有那些工具你可以写一个傻程序:
|
|
||||||
|
|
||||||
char str[] = "\xXX\xXX\xXX...";
|
|
||||||
main(){}
|
|
||||||
|
|
||||||
并用gcc -g编译它然后执行“disassemble str”(XX部分是由Oops报告的值-你可以仅剪切
|
|
||||||
粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。
|
|
||||||
|
|
||||||
另外,你可以用scripts/decodecode这个shell脚本。它的使用方法是:
|
|
||||||
decodecode < oops.txt
|
|
||||||
|
|
||||||
“Code”之后的十六进制字节可能(在某些架构上)有一些当前指令之前的指令字节以及
|
|
||||||
当前和之后的指令字节
|
|
||||||
|
|
||||||
Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
|
|
||||||
64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
|
|
||||||
7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
|
|
||||||
|
|
||||||
最后,如果你想知道代码来自哪里,你可以:
|
|
||||||
|
|
||||||
cd /usr/src/linux
|
|
||||||
make fs/buffer.s # 或任何产生BUG的文件
|
|
||||||
|
|
||||||
然后你会比gdb反汇编更清楚的知道发生了什么。
|
|
||||||
|
|
||||||
现在,问题是把你所拥有的所有数据结合起来:C源码(关于它应该怎样的一般知识),
|
|
||||||
汇编代码及其反汇编得到的代码(另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
|
|
||||||
指针有用,而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
|
|
||||||
)。
|
|
||||||
|
|
||||||
实际上,你仅需看看哪里不匹配(这个例子是“Code”反汇编和编译器生成的代码不匹配)。
|
|
||||||
然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
|
|
||||||
空指针是怎么出现的,还有检查它是否合法..
|
|
||||||
|
|
||||||
现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
|
|
||||||
只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
|
|
||||||
程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
|
|
||||||
仅仅是找出正确的序列也确实需要相当扎实的内核知识)
|
|
||||||
|
|
||||||
_有时_会发生这种情况,我仅看到崩溃中的反汇编代码序列, 然后我马上就明白问题出在
|
|
||||||
哪里。这时我才意识到自己干这个工作已经太长时间了;-)
|
|
||||||
|
|
||||||
Linus
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
关于Oops跟踪的注解:
|
|
||||||
|
|
||||||
为了帮助Linus和其它内核开发者,klogd纳入了大量的支持来处理保护错误。为了拥有对
|
|
||||||
地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。
|
|
||||||
|
|
||||||
当保护错误发生时,klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
|
|
||||||
号。
|
|
||||||
|
|
||||||
klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
|
|
||||||
一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
|
|
||||||
map文件。关于klogd怎样搜索map文件请参看klogd手册页。
|
|
||||||
|
|
||||||
动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
|
|
||||||
里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。
|
|
||||||
|
|
||||||
内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
|
|
||||||
klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。
|
|
||||||
|
|
||||||
至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
|
|
||||||
以从模块中输出符号信息。
|
|
||||||
|
|
||||||
因为内核模块环境可能是动态的,所以必须有一种机制当模块环境发生改变时来通知klogd
|
|
||||||
守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号,告知符
|
|
||||||
号信息应该被刷新了。 更多信息请参看klogd手册页。
|
|
||||||
|
|
||||||
sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
|
|
||||||
会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
|
|
||||||
错误的无缝支持。
|
|
||||||
|
|
||||||
以下是被klogd处理过的发生在可装载模块中的一个保护错误例子:
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
|
|
||||||
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
|
|
||||||
Aug 29 09:51:01 blizard kernel: *pde = 00000000
|
|
||||||
Aug 29 09:51:01 blizard kernel: Oops: 0002
|
|
||||||
Aug 29 09:51:01 blizard kernel: CPU: 0
|
|
||||||
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
|
|
||||||
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
|
|
||||||
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
|
|
||||||
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
|
|
||||||
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
|
|
||||||
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
|
|
||||||
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
|
|
||||||
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
|
|
||||||
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
|
|
||||||
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
|
|
||||||
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
|
|
||||||
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
|
|
||||||
820 4th St. N.
|
|
||||||
Fargo, ND 58122
|
|
||||||
Phone: 701-234-7556
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
受污染的内核
|
|
||||||
|
|
||||||
一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
|
|
||||||
染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。
|
|
||||||
|
|
||||||
1:'G'如果所有装载的模块都有GPL或相容的许可证,'P'如果装载了任何的专有模块。
|
|
||||||
没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
|
|
||||||
认定是专有的。
|
|
||||||
|
|
||||||
2:'F'如果有任何通过“insmod -f”被强制装载的模块,' '如果所有模块都被正常装载。
|
|
||||||
|
|
||||||
3:'S'如果oops发生在SMP内核中,运行于没有证明安全运行多处理器的硬件。 当前这种
|
|
||||||
情况仅限于几种不支持SMP的速龙处理器。
|
|
||||||
|
|
||||||
4:'R'如果模块通过“insmod -f”被强制装载,' '如果所有模块都被正常装载。
|
|
||||||
|
|
||||||
5:'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。
|
|
||||||
|
|
||||||
6:'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。
|
|
||||||
|
|
||||||
7:'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。
|
|
||||||
|
|
||||||
8:'D'如果内核刚刚死掉,比如有OOPS或者BUG。
|
|
||||||
|
|
||||||
使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
|
|
||||||
生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
|
|
||||||
以表明内核不再值得信任。
|
|
@ -1,21 +1,23 @@
|
|||||||
.. include:: ../disclaimer-zh_CN.rst
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
:Original: :ref:`Documentation/process/coding-style.rst <codingstyle>`
|
:Original: Documentation/process/coding-style.rst
|
||||||
|
|
||||||
.. _cn_codingstyle:
|
.. _cn_codingstyle:
|
||||||
|
|
||||||
译者::
|
:译者:
|
||||||
|
- 张乐 Zhang Le <r0bertz@gentoo.org>
|
||||||
|
- Andy Deng <theandy.deng@gmail.com>
|
||||||
|
- 吴想成 <bobwxc@email.cn>
|
||||||
|
|
||||||
中文版维护者: 张乐 Zhang Le <r0bertz@gentoo.org>
|
:校译:
|
||||||
中文版翻译者: 张乐 Zhang Le <r0bertz@gentoo.org>
|
- 王聪 Wang Cong <xiyou.wangcong@gmail.com>
|
||||||
中文版校译者: 王聪 Wang Cong <xiyou.wangcong@gmail.com>
|
- wheelz <kernel.zeng@gmail.com>
|
||||||
wheelz <kernel.zeng@gmail.com>
|
- 管旭东 Xudong Guan <xudong.guan@gmail.com>
|
||||||
管旭东 Xudong Guan <xudong.guan@gmail.com>
|
- Li Zefan <lizf@cn.fujitsu.com>
|
||||||
Li Zefan <lizf@cn.fujitsu.com>
|
- Wang Chen <wangchen@cn.fujitsu.com>
|
||||||
Wang Chen <wangchen@cn.fujitsu.com>
|
|
||||||
|
|
||||||
Linux 内核代码风格
|
Linux 内核代码风格
|
||||||
=========================
|
==================
|
||||||
|
|
||||||
这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,
|
这是一个简短的文档,描述了 linux 内核的首选代码风格。代码风格是因人而异的,
|
||||||
而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则
|
而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则
|
||||||
@ -29,7 +31,7 @@ Linux 内核代码风格
|
|||||||
|
|
||||||
|
|
||||||
1) 缩进
|
1) 缩进
|
||||||
--------------
|
-------
|
||||||
|
|
||||||
制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至
|
制表符是 8 个字符,所以缩进也是 8 个字符。有些异端运动试图将缩进变为 4 (甚至
|
||||||
2!) 字符深,这几乎相当于尝试将圆周率的值定义为 3。
|
2!) 字符深,这几乎相当于尝试将圆周率的值定义为 3。
|
||||||
@ -73,6 +75,22 @@ Linux 内核代码风格
|
|||||||
if (condition) do_this;
|
if (condition) do_this;
|
||||||
do_something_everytime;
|
do_something_everytime;
|
||||||
|
|
||||||
|
不要使用逗号来避免使用大括号:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
if (condition)
|
||||||
|
do_this(), do_that();
|
||||||
|
|
||||||
|
使用大括号包裹多语句:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
if (condition) {
|
||||||
|
do_this();
|
||||||
|
do_that();
|
||||||
|
}
|
||||||
|
|
||||||
也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
|
也不要在一行里放多个赋值语句。内核代码风格超级简单。就是避免可能导致别人误读
|
||||||
的表达式。
|
的表达式。
|
||||||
|
|
||||||
@ -83,20 +101,25 @@ Linux 内核代码风格
|
|||||||
|
|
||||||
|
|
||||||
2) 把长的行和字符串打散
|
2) 把长的行和字符串打散
|
||||||
------------------------------
|
-----------------------
|
||||||
|
|
||||||
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
|
代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性。
|
||||||
|
|
||||||
每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。
|
每一行的长度的限制是 80 列,我们强烈建议您遵守这个惯例。
|
||||||
|
|
||||||
长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不
|
长于 80 列的语句要打散成有意义的片段。除非超过 80 列能显著增加可读性,并且不
|
||||||
会隐藏信息。子片段要明显短于母片段,并明显靠右。这同样适用于有着很长参数列表
|
会隐藏信息。
|
||||||
的函数头。然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就
|
|
||||||
|
子片段要明显短于母片段,并明显靠右。一种非常常用的样式是将子体与函数左括号对齐。
|
||||||
|
|
||||||
|
这同样适用于有着很长参数列表的函数头。
|
||||||
|
|
||||||
|
然而,绝对不要打散对用户可见的字符串,例如 printk 信息,因为这样就
|
||||||
很难对它们 grep。
|
很难对它们 grep。
|
||||||
|
|
||||||
|
|
||||||
3) 大括号和空格的放置
|
3) 大括号和空格的放置
|
||||||
------------------------------
|
---------------------
|
||||||
|
|
||||||
C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放
|
C 语言风格中另外一个常见问题是大括号的放置。和缩进大小不同,选择或弃用某种放
|
||||||
置策略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示
|
置策略并没有多少技术上的原因,不过首选的方式,就像 Kernighan 和 Ritchie 展示
|
||||||
@ -132,12 +155,12 @@ C 语言风格中另外一个常见问题是大括号的放置。和缩进大小
|
|||||||
body of function
|
body of function
|
||||||
}
|
}
|
||||||
|
|
||||||
全世界的异端可能会抱怨这个不一致性是... 呃... 不一致的,不过所有思维健全的人
|
全世界的异端可能会抱怨这个不一致性是……呃……不一致,不过所有思维健全的人
|
||||||
都知道 (a) K&R 是 **正确的** 并且 (b) K&R 是正确的。此外,不管怎样函数都是特
|
都知道 (a) K&R 是 **正确的** 并且 (b) K&R 是正确的。此外,不管怎样函数都是特
|
||||||
殊的 (C 函数是不能嵌套的)。
|
殊的 (C 函数是不能嵌套的)。
|
||||||
|
|
||||||
注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语
|
注意结束大括号独自占据一行,除非它后面跟着同一个语句的剩余部分,也就是 do 语
|
||||||
句中的 "while" 或者 if 语句中的 "else",像这样:
|
句中的 ``while`` 或者 if 语句中的 ``else`` ,像这样:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@ -191,7 +214,7 @@ C 语言风格中另外一个常见问题是大括号的放置。和缩进大小
|
|||||||
}
|
}
|
||||||
|
|
||||||
3.1) 空格
|
3.1) 空格
|
||||||
********************
|
*********
|
||||||
|
|
||||||
Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字
|
Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关键字。(大多数) 关键字
|
||||||
后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__,这
|
后要加一个空格。值得注意的例外是 sizeof, typeof, alignof 和 __attribute__,这
|
||||||
@ -254,7 +277,7 @@ Linux 内核的空格使用方式 (主要) 取决于它是用于函数还是关
|
|||||||
|
|
||||||
|
|
||||||
4) 命名
|
4) 命名
|
||||||
------------------------------
|
-------
|
||||||
|
|
||||||
C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,
|
C 是一个简朴的语言,你的命名也应该这样。和 Modula-2 和 Pascal 程序员不同,
|
||||||
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
|
C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字。C 程序员会
|
||||||
@ -275,11 +298,31 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
|
|||||||
可能的话。类似的, ``tmp`` 可以用来称呼任意类型的临时变量。
|
可能的话。类似的, ``tmp`` 可以用来称呼任意类型的临时变量。
|
||||||
|
|
||||||
如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
|
如果你怕混淆了你的本地变量名,你就遇到另一个问题了,叫做函数增长荷尔蒙失衡综
|
||||||
合症。请看第六章 (函数)。
|
合征。请看第六章 (函数)。
|
||||||
|
|
||||||
|
对于符号名称和文档,避免引入新的“master/slave”(或独立于“master”的“slave”)
|
||||||
|
和“blacklist/whitelist”。
|
||||||
|
|
||||||
|
“master/slave”推荐替换为:
|
||||||
|
'{primary,main} / {secondary,replica,subordinate}'
|
||||||
|
'{initiator,requester} / {target,responder}'
|
||||||
|
'{controller,host} / {device,worker,proxy}'
|
||||||
|
'leader/follower'
|
||||||
|
'director/performer'
|
||||||
|
|
||||||
|
“blacklist/whitelist”推荐替换为:
|
||||||
|
'denylist/allowlist'
|
||||||
|
'blocklist/passlist'
|
||||||
|
|
||||||
|
引入新用法的例外情况是:维护用户空间ABI/API,或更新现有(截至2020年)硬件或
|
||||||
|
协议规范的代码时要求这些术语。对于新规范,尽可能将术语的规范用法转换为内核
|
||||||
|
编码标准。
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
以上主从、黑白名单规则不适用于中文文档,请勿更改中文术语!
|
||||||
|
|
||||||
5) Typedef
|
5) Typedef
|
||||||
-----------
|
----------
|
||||||
|
|
||||||
不要使用类似 ``vps_t`` 之类的东西。
|
不要使用类似 ``vps_t`` 之类的东西。
|
||||||
|
|
||||||
@ -308,7 +351,7 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
不透明性和 "访问函数" 本身是不好的。我们使用 pte_t 等类型的原因在于真
|
不透明性和“访问函数”本身是不好的。我们使用 pte_t 等类型的原因在于真
|
||||||
的是完全没有任何共用的可访问信息。
|
的是完全没有任何共用的可访问信息。
|
||||||
|
|
||||||
(b) 清楚的整数类型,如此,这层抽象就可以 **帮助** 消除到底是 ``int`` 还是
|
(b) 清楚的整数类型,如此,这层抽象就可以 **帮助** 消除到底是 ``int`` 还是
|
||||||
@ -353,7 +396,7 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
|
|||||||
|
|
||||||
|
|
||||||
6) 函数
|
6) 函数
|
||||||
------------------------------
|
-------
|
||||||
|
|
||||||
函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们
|
函数应该简短而漂亮,并且只完成一件事情。函数应该可以一屏或者两屏显示完 (我们
|
||||||
都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。
|
都知道 ISO/ANSI 屏幕大小是 80x24),只做一件事情,而且把它做好。
|
||||||
@ -383,12 +426,46 @@ C 程序员不使用类似 ThisVariableIsATemporaryCounter 这样华丽的名字
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(system_is_up);
|
EXPORT_SYMBOL(system_is_up);
|
||||||
|
|
||||||
在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,在
|
6.1) 函数原型
|
||||||
|
*************
|
||||||
|
|
||||||
|
在函数原型中包含参数名和它们的数据类型。虽然 C 语言里没有这样的要求,但在
|
||||||
Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
|
Linux 里这是提倡的做法,因为这样可以很简单的给读者提供更多的有价值的信息。
|
||||||
|
|
||||||
|
不要在函数声明里使用 ``extern`` 关键字,因为这会导致代码行变长,并且不是严格
|
||||||
|
必需的。
|
||||||
|
|
||||||
|
写函数原型时,请保持 `元素顺序规则 <https://lore.kernel.org/mm-commits/CAHk-=wiOCLRny5aifWNhr621kYrJwhfURsa0vFPeUEm8mF0ufg@mail.gmail.com/>`_ 。
|
||||||
|
例如下列函数声明::
|
||||||
|
|
||||||
|
__init void * __must_check action(enum magic value, size_t size, u8 count,
|
||||||
|
char *fmt, ...) __printf(4, 5) __malloc;
|
||||||
|
|
||||||
|
推荐的函数原型元素顺序是:
|
||||||
|
|
||||||
|
- 储存类型(下方的 ``static __always_inline`` ,注意 ``__always_inline``
|
||||||
|
技术上来讲是个属性但被当做 ``inline`` )
|
||||||
|
- 储存类型属性(上方的 ``__init`` ——即节声明,但也像 ``__cold`` )
|
||||||
|
- 返回类型(上方的 ``void *`` )
|
||||||
|
- 返回类型属性(上方的 ``__must_check`` )
|
||||||
|
- 函数名(上方的 ``action`` )
|
||||||
|
- 函数参数(上方的 ``(enum magic value, size_t size, u8 count, char *fmt, ...)`` ,
|
||||||
|
注意必须写上参数名)
|
||||||
|
- 函数参数属性(上方的 ``__printf(4, 5)`` )
|
||||||
|
- 函数行为属性(上方的 ``__malloc`` )
|
||||||
|
|
||||||
|
请注意,对于函数 **定义** (即实际函数体),编译器不允许在函数参数之后添加函
|
||||||
|
数参数属性。在这种情况下,它们应该跟随存储类型属性(例如,与上面的 **声明**
|
||||||
|
示例相比,请注意下面的 ``__printf(4, 5)`` 的位置发生了变化)::
|
||||||
|
|
||||||
|
static __always_inline __init __printf(4, 5) void * __must_check action(enum magic value,
|
||||||
|
size_t size, u8 count, char *fmt, ...) __malloc
|
||||||
|
{
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
7) 集中的函数退出途径
|
7) 集中的函数退出途径
|
||||||
------------------------------
|
---------------------
|
||||||
|
|
||||||
虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体
|
虽然被某些人声称已经过时,但是 goto 语句的等价物还是经常被编译器所使用,具体
|
||||||
形式是无条件跳转指令。
|
形式是无条件跳转指令。
|
||||||
@ -432,7 +509,7 @@ Linux 里这是提倡的做法,因为这样可以很简单的给读者提供
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
一个需要注意的常见错误是 ``一个 err 错误`` ,就像这样:
|
一个需要注意的常见错误是 ``单 err 错误`` ,就像这样:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@ -456,19 +533,19 @@ Linux 里这是提倡的做法,因为这样可以很简单的给读者提供
|
|||||||
|
|
||||||
|
|
||||||
8) 注释
|
8) 注释
|
||||||
------------------------------
|
-------
|
||||||
|
|
||||||
注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:
|
注释是好的,不过有过度注释的危险。永远不要在注释里解释你的代码是如何运作的:
|
||||||
更好的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。
|
更好的做法是让别人一看你的代码就可以明白,解释写的很差的代码是浪费时间。
|
||||||
|
|
||||||
一般的,你想要你的注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把
|
一般来说你用注释告诉别人你的代码做了什么,而不是怎么做的。也请你不要把
|
||||||
注释放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能
|
注释放在一个函数体内部:如果函数复杂到你需要独立的注释其中的一部分,你很可能
|
||||||
需要回到第六章看一看。你可以做一些小注释来注明或警告某些很聪明 (或者槽糕) 的
|
需要回到第六章看一看。你可以做一些小注释来注明或警告某些很聪明 (或者槽糕) 的
|
||||||
做法,但不要加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,
|
做法,但不要加太多。你应该做的,是把注释放在函数的头部,告诉人们它做了什么,
|
||||||
也可以加上它做这些事情的原因。
|
也可以加上它做这些事情的原因。
|
||||||
|
|
||||||
当注释内核 API 函数时,请使用 kernel-doc 格式。请看
|
当注释内核 API 函数时,请使用 kernel-doc 格式。详见
|
||||||
Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
|
Documentation/translations/zh_CN/doc-guide/index.rst 和 scripts/kernel-doc 。
|
||||||
|
|
||||||
长 (多行) 注释的首选风格是:
|
长 (多行) 注释的首选风格是:
|
||||||
|
|
||||||
@ -500,17 +577,18 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
|
|||||||
|
|
||||||
|
|
||||||
9) 你已经把事情弄糟了
|
9) 你已经把事情弄糟了
|
||||||
------------------------------
|
---------------------
|
||||||
|
|
||||||
这没什么,我们都是这样。可能你的使用了很长时间 Unix 的朋友已经告诉你
|
这没什么,我们都是这样。可能你长期使用 Unix 的朋友已经告诉你
|
||||||
``GNU emacs`` 能自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它
|
``GNU emacs`` 能自动帮你格式化 C 源代码,而且你也注意到了,确实是这样,不过它
|
||||||
所使用的默认值和我们想要的相去甚远 (实际上,甚至比随机打的还要差——无数个猴子
|
所使用的默认值和我们想要的相去甚远 (实际上,甚至比随机打的还要差——无数个猴子
|
||||||
在 GNU emacs 里打字永远不会创造出一个好程序) (译注:Infinite Monkey Theorem)
|
在 GNU emacs 里打字永远不会创造出一个好程序)
|
||||||
|
*(译注:Infinite Monkey Theorem)*
|
||||||
|
|
||||||
所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,
|
所以你要么放弃 GNU emacs,要么改变它让它使用更合理的设定。要采用后一个方案,
|
||||||
你可以把下面这段粘贴到你的 .emacs 文件里。
|
你可以把下面这段粘贴到你的 .emacs 文件里。
|
||||||
|
|
||||||
.. code-block:: none
|
.. code-block:: elisp
|
||||||
|
|
||||||
(defun c-lineup-arglist-tabs-only (ignored)
|
(defun c-lineup-arglist-tabs-only (ignored)
|
||||||
"Line up argument lists by tabs, not spaces"
|
"Line up argument lists by tabs, not spaces"
|
||||||
@ -529,7 +607,7 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
|
|||||||
(c-offsets-alist . (
|
(c-offsets-alist . (
|
||||||
(arglist-close . c-lineup-arglist-tabs-only)
|
(arglist-close . c-lineup-arglist-tabs-only)
|
||||||
(arglist-cont-nonempty .
|
(arglist-cont-nonempty .
|
||||||
(c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
|
(c-lineup-gcc-asm-reg c-lineup-arglist-tabs-only))
|
||||||
(arglist-intro . +)
|
(arglist-intro . +)
|
||||||
(brace-list-intro . +)
|
(brace-list-intro . +)
|
||||||
(c . c-lineup-C-comments)
|
(c . c-lineup-C-comments)
|
||||||
@ -573,9 +651,14 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
|
|||||||
``indent`` 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册。
|
``indent`` 有很多选项,特别是重新格式化注释的时候,你可能需要看一下它的手册。
|
||||||
不过记住: ``indent`` 不能修正坏的编程习惯。
|
不过记住: ``indent`` 不能修正坏的编程习惯。
|
||||||
|
|
||||||
|
请注意,您还可以使用 ``clang-format`` 工具帮助您处理这些规则,快速自动重新格
|
||||||
|
式化部分代码,并审阅整个文件以发现代码风格错误、打字错误和可能的改进。它还可
|
||||||
|
以方便地排序 ``#include`` ,对齐变量/宏,重排文本和其他类似任务。
|
||||||
|
详见 Documentation/process/clang-format.rst 。
|
||||||
|
|
||||||
|
|
||||||
10) Kconfig 配置文件
|
10) Kconfig 配置文件
|
||||||
------------------------------
|
--------------------
|
||||||
|
|
||||||
对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式有所不同。紧挨着
|
对于遍布源码树的所有 Kconfig* 配置文件来说,它们缩进方式有所不同。紧挨着
|
||||||
``config`` 定义的行,用一个制表符缩进,然而 help 信息的缩进则额外增加 2 个空
|
``config`` 定义的行,用一个制表符缩进,然而 help 信息的缩进则额外增加 2 个空
|
||||||
@ -598,11 +681,11 @@ Documentation/doc-guide/ 和 scripts/kernel-doc 以获得详细信息。
|
|||||||
depends on ADFS_FS
|
depends on ADFS_FS
|
||||||
...
|
...
|
||||||
|
|
||||||
要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst。
|
要查看配置文件的完整文档,请看 Documentation/kbuild/kconfig-language.rst 。
|
||||||
|
|
||||||
|
|
||||||
11) 数据结构
|
11) 数据结构
|
||||||
------------------------------
|
------------
|
||||||
|
|
||||||
如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引
|
如果一个数据结构,在创建和销毁它的单线执行环境之外可见,那么它必须要有一个引
|
||||||
用计数器。内核里没有垃圾收集 (并且内核之外的垃圾收集慢且效率低下),这意味着你
|
用计数器。内核里没有垃圾收集 (并且内核之外的垃圾收集慢且效率低下),这意味着你
|
||||||
@ -626,7 +709,7 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
|
|||||||
|
|
||||||
|
|
||||||
12) 宏,枚举和RTL
|
12) 宏,枚举和RTL
|
||||||
------------------------------
|
-----------------
|
||||||
|
|
||||||
用于定义常量的宏的名字及枚举里的标签需要大写。
|
用于定义常量的宏的名字及枚举里的标签需要大写。
|
||||||
|
|
||||||
@ -638,7 +721,7 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
|
|||||||
|
|
||||||
宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。
|
宏的名字请用大写字母,不过形如函数的宏的名字可以用小写字母。
|
||||||
|
|
||||||
一般的,如果能写成内联函数就不要写成像函数的宏。
|
通常如果能写成内联函数就不要写成像函数的宏。
|
||||||
|
|
||||||
含有多个语句的宏应该被包含在一个 do-while 代码块里:
|
含有多个语句的宏应该被包含在一个 do-while 代码块里:
|
||||||
|
|
||||||
@ -696,18 +779,18 @@ mm_count),和文件系统 (``struct super_block``: s_count 和 s_active) 中
|
|||||||
(ret); \
|
(ret); \
|
||||||
})
|
})
|
||||||
|
|
||||||
ret 是本地变量的通用名字 - __foo_ret 更不容易与一个已存在的变量冲突。
|
ret 是本地变量的通用名字—— __foo_ret 更不容易与一个已存在的变量冲突。
|
||||||
|
|
||||||
cpp 手册对宏的讲解很详细。gcc internals 手册也详细讲解了 RTL,内核里的汇编语
|
cpp 手册对宏的讲解很详细。gcc internals 手册也详细讲解了 RTL,内核里的汇编语
|
||||||
言经常用到它。
|
言经常用到它。
|
||||||
|
|
||||||
|
|
||||||
13) 打印内核消息
|
13) 打印内核消息
|
||||||
------------------------------
|
----------------
|
||||||
|
|
||||||
内核开发者应该是受过良好教育的。请一定注意内核信息的拼写,以给人以好的印象。
|
内核开发者应该看起来有文化。请一定注意内核信息的拼写,以给人良好的印象。
|
||||||
不要用不规范的单词比如 ``dont``,而要用 ``do not`` 或者 ``don't`` 。保证这些信
|
不要用不规范的单词比如 ``dont``,而要用 ``do not`` 或者 ``don't`` 。保证这些信
|
||||||
息简单明了,无歧义。
|
息简单明了、无歧义。
|
||||||
|
|
||||||
内核信息不必以英文句号结束。
|
内核信息不必以英文句号结束。
|
||||||
|
|
||||||
@ -724,17 +807,18 @@ dev_info() 等等。对于那些不和某个特定设备相关连的信息,<li
|
|||||||
或设定了 CONFIG_DYNAMIC_DEBUG。实际这同样是为了 dev_dbg(),一个相关约定是在一
|
或设定了 CONFIG_DYNAMIC_DEBUG。实际这同样是为了 dev_dbg(),一个相关约定是在一
|
||||||
个已经开启了 DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()。
|
个已经开启了 DEBUG 时,使用 VERBOSE_DEBUG 来添加 dev_vdbg()。
|
||||||
|
|
||||||
许多子系统拥有 Kconfig 调试选项来开启 -DDEBUG 在对应的 Makefile 里面;在其他
|
许多子系统拥有 Kconfig 调试选项来开启对应 Makefile 里面的 -DDEBUG;在其他
|
||||||
情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,
|
情况下,特殊文件使用 #define DEBUG。当一条调试信息需要被无条件打印时,例如,
|
||||||
如果已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
|
如果已经包含一个调试相关的 #ifdef 条件,printk(KERN_DEBUG ...) 就可被使用。
|
||||||
|
|
||||||
|
|
||||||
14) 分配内存
|
14) 分配内存
|
||||||
------------------------------
|
------------
|
||||||
|
|
||||||
内核提供了下面的一般用途的内存分配函数:
|
内核提供了下面的一般用途的内存分配函数:
|
||||||
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
|
kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
|
||||||
请参考 API 文档以获取有关它们的详细信息。
|
请参考 API 文档以获取有关它们的详细信息:
|
||||||
|
Documentation/translations/zh_CN/core-api/memory-allocation.rst 。
|
||||||
|
|
||||||
传递结构体大小的首选形式是这样的:
|
传递结构体大小的首选形式是这样的:
|
||||||
|
|
||||||
@ -761,11 +845,13 @@ kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc() 和 vzalloc()。
|
|||||||
|
|
||||||
p = kcalloc(n, sizeof(...), ...);
|
p = kcalloc(n, sizeof(...), ...);
|
||||||
|
|
||||||
两种形式检查分配大小 n * sizeof(...) 的溢出,如果溢出返回 NULL。
|
两种形式都会检查分配 n * sizeof(...) 大小时内存的溢出,如果溢出返回 NULL。
|
||||||
|
|
||||||
|
在没有 __GFP_NOWARN 的情况下使用时,这些通用分配函数都会在失败时发起堆栈转储,
|
||||||
|
因此当返回NULL时,没有必要发出额外的失败消息。
|
||||||
|
|
||||||
15) 内联弊病
|
15) 内联弊病
|
||||||
------------------------------
|
------------
|
||||||
|
|
||||||
有一个常见的误解是 ``内联`` 是 gcc 提供的可以让代码运行更快的一个选项。虽然使
|
有一个常见的误解是 ``内联`` 是 gcc 提供的可以让代码运行更快的一个选项。虽然使
|
||||||
用内联函数有时候是恰当的 (比如作为一种替代宏的方式,请看第十二章),不过很多情
|
用内联函数有时候是恰当的 (比如作为一种替代宏的方式,请看第十二章),不过很多情
|
||||||
@ -786,7 +872,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
|
|||||||
|
|
||||||
|
|
||||||
16) 函数返回值及命名
|
16) 函数返回值及命名
|
||||||
------------------------------
|
--------------------
|
||||||
|
|
||||||
函数可以返回多种不同类型的值,最常见的一种是表明函数执行成功或者失败的值。这样
|
函数可以返回多种不同类型的值,最常见的一种是表明函数执行成功或者失败的值。这样
|
||||||
的一个值可以表示为一个错误代码整数 (-Exxx=失败,0=成功) 或者一个 ``成功``
|
的一个值可以表示为一个错误代码整数 (-Exxx=失败,0=成功) 或者一个 ``成功``
|
||||||
@ -797,7 +883,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
|
|||||||
产生这种 bug,请遵循下面的惯例::
|
产生这种 bug,请遵循下面的惯例::
|
||||||
|
|
||||||
如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代
|
如果函数的名字是一个动作或者强制性的命令,那么这个函数应该返回错误代
|
||||||
码整数。如果是一个判断,那么函数应该返回一个 "成功" 布尔值。
|
码整数。如果是一个判断,那么函数应该返回一个“成功”布尔值。
|
||||||
|
|
||||||
比如, ``add work`` 是一个命令,所以 add_work() 在成功时返回 0,在失败时返回
|
比如, ``add work`` 是一个命令,所以 add_work() 在成功时返回 0,在失败时返回
|
||||||
-EBUSY。类似的,因为 ``PCI device present`` 是一个判断,所以 pci_dev_present()
|
-EBUSY。类似的,因为 ``PCI device present`` 是一个判断,所以 pci_dev_present()
|
||||||
@ -806,13 +892,35 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
|
|||||||
所有 EXPORTed 函数都必须遵守这个惯例,所有的公共函数也都应该如此。私有
|
所有 EXPORTed 函数都必须遵守这个惯例,所有的公共函数也都应该如此。私有
|
||||||
(static) 函数不需要如此,但是我们也推荐这样做。
|
(static) 函数不需要如此,但是我们也推荐这样做。
|
||||||
|
|
||||||
返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。一般的,
|
返回值是实际计算结果而不是计算是否成功的标志的函数不受此惯例的限制。通常
|
||||||
他们通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,
|
他们通过返回一些正常值范围之外的结果来表示出错。典型的例子是返回指针的函数,
|
||||||
他们使用 NULL 或者 ERR_PTR 机制来报告错误。
|
他们使用 NULL 或者 ERR_PTR 机制来报告错误。
|
||||||
|
|
||||||
|
17) 使用布尔类型
|
||||||
|
----------------
|
||||||
|
|
||||||
17) 不要重新发明内核宏
|
Linux内核布尔(bool)类型是C99 _Bool类型的别名。布尔值只能为0或1,而对布尔的
|
||||||
------------------------------
|
隐式或显式转换将自动将值转换为true或false。在使用布尔类型时 **不需要** 构造,
|
||||||
|
它会消除一类错误。
|
||||||
|
|
||||||
|
使用布尔值时,应使用true和false定义,而不是1和0。
|
||||||
|
|
||||||
|
布尔函数返回类型和堆栈变量总是可以在适当的时候使用。鼓励使用布尔来提高可读性,
|
||||||
|
并且布尔值在存储时通常比“int”更好。
|
||||||
|
|
||||||
|
如果缓存行布局或值的大小很重要,请不要使用布尔,因为其大小和对齐方式根据编译
|
||||||
|
的体系结构而不同。针对对齐和大小进行优化的结构体不应使用布尔。
|
||||||
|
|
||||||
|
如果一个结构体有多个true/false值,请考虑将它们合并为具有1比特成员的位域,或使
|
||||||
|
用适当的固定宽度类型,如u8。
|
||||||
|
|
||||||
|
类似地,对于函数参数,多个true/false值可以合并为单个按位的“标志”参数,如果调
|
||||||
|
用点具有裸true/false常量,“标志”参数通常是更具可读性的替代方法。
|
||||||
|
|
||||||
|
总之,在结构体和参数中有限地使用布尔可以提高可读性。
|
||||||
|
|
||||||
|
18) 不要重新发明内核宏
|
||||||
|
----------------------
|
||||||
|
|
||||||
头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些
|
头文件 include/linux/kernel.h 包含了一些宏,你应该使用它们,而不要自己写一些
|
||||||
它们的变种。比如,如果你需要计算一个数组的长度,使用这个宏
|
它们的变种。比如,如果你需要计算一个数组的长度,使用这个宏
|
||||||
@ -832,11 +940,11 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
|
|||||||
在你的代码里自己重新定义。
|
在你的代码里自己重新定义。
|
||||||
|
|
||||||
|
|
||||||
18) 编辑器模式行和其他需要罗嗦的事情
|
19) 编辑器模式行和其他需要罗嗦的事情
|
||||||
--------------------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs
|
有一些编辑器可以解释嵌入在源文件里的由一些特殊标记标明的配置信息。比如,emacs
|
||||||
能够解释被标记成这样的行:
|
能够解析被标记成这样的行:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@ -852,7 +960,7 @@ inline gcc 也可以自动使其内联。而且其他用户可能会要求移除
|
|||||||
End:
|
End:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Vim 能够解释这样的标记:
|
Vim 能够解析这样的标记:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@ -863,8 +971,8 @@ Vim 能够解释这样的标记:
|
|||||||
的模式,或者使用其他可以产生正确的缩进的巧妙方法。
|
的模式,或者使用其他可以产生正确的缩进的巧妙方法。
|
||||||
|
|
||||||
|
|
||||||
19) 内联汇编
|
20) 内联汇编
|
||||||
------------------------------
|
------------
|
||||||
|
|
||||||
在特定架构的代码中,你可能需要内联汇编与 CPU 和平台相关功能连接。需要这么做时
|
在特定架构的代码中,你可能需要内联汇编与 CPU 和平台相关功能连接。需要这么做时
|
||||||
就不要犹豫。然而,当 C 可以完成工作时,不要平白无故地使用内联汇编。在可能的情
|
就不要犹豫。然而,当 C 可以完成工作时,不要平白无故地使用内联汇编。在可能的情
|
||||||
@ -880,8 +988,8 @@ Vim 能够解释这样的标记:
|
|||||||
移除了。你不必总是这样做,尽管,这不必要的举动会限制优化。
|
移除了。你不必总是这样做,尽管,这不必要的举动会限制优化。
|
||||||
|
|
||||||
在写一个包含多条指令的单个内联汇编语句时,把每条指令用引号分割而且各占一行,
|
在写一个包含多条指令的单个内联汇编语句时,把每条指令用引号分割而且各占一行,
|
||||||
除了最后一条指令外,在每个指令结尾加上 \n\t,让汇编输出时可以正确地缩进下一条
|
除了最后一条指令外,在每个指令结尾加上 ``\n\t`` ,让汇编输出时可以正确地缩进
|
||||||
指令:
|
下一条指令:
|
||||||
|
|
||||||
.. code-block:: c
|
.. code-block:: c
|
||||||
|
|
||||||
@ -890,10 +998,10 @@ Vim 能够解释这样的标记:
|
|||||||
: /* outputs */ : /* inputs */ : /* clobbers */);
|
: /* outputs */ : /* inputs */ : /* clobbers */);
|
||||||
|
|
||||||
|
|
||||||
20) 条件编译
|
21) 条件编译
|
||||||
------------------------------
|
------------
|
||||||
|
|
||||||
只要可能,就不要在 .c 文件里面使用预处理条件 (#if, #ifdef);这样做让代码更难
|
只要可能,就不要在 .c 文件里面使用预处理条件 (#if, #ifdef);这样做会让代码更难
|
||||||
阅读并且更难去跟踪逻辑。替代方案是,在头文件中用预处理条件提供给那些 .c 文件
|
阅读并且更难去跟踪逻辑。替代方案是,在头文件中用预处理条件提供给那些 .c 文件
|
||||||
使用,再给 #else 提供一个空桩 (no-op stub) 版本,然后在 .c 文件内无条件地调用
|
使用,再给 #else 提供一个空桩 (no-op stub) 版本,然后在 .c 文件内无条件地调用
|
||||||
那些 (定义在头文件内的) 函数。这样做,编译器会避免为桩函数 (stub) 的调用生成
|
那些 (定义在头文件内的) 函数。这样做,编译器会避免为桩函数 (stub) 的调用生成
|
||||||
@ -904,8 +1012,8 @@ Vim 能够解释这样的标记:
|
|||||||
条件到这个辅助函数内。
|
条件到这个辅助函数内。
|
||||||
|
|
||||||
如果你有一个在特定配置中,可能变成未使用的函数或变量,编译器会警告它定义了但
|
如果你有一个在特定配置中,可能变成未使用的函数或变量,编译器会警告它定义了但
|
||||||
未使用,把它标记为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而,如
|
未使用,请把它标记为 __maybe_unused 而不是将它包含在一个预处理条件中。(然而,
|
||||||
果一个函数或变量总是未使用,就直接删除它。)
|
如果一个函数或变量总是未使用,就直接删除它。)
|
||||||
|
|
||||||
在代码中,尽可能地使用 IS_ENABLED 宏来转化某个 Kconfig 标记为 C 的布尔
|
在代码中,尽可能地使用 IS_ENABLED 宏来转化某个 Kconfig 标记为 C 的布尔
|
||||||
表达式,并在一般的 C 条件中使用它:
|
表达式,并在一般的 C 条件中使用它:
|
||||||
@ -931,23 +1039,45 @@ Vim 能够解释这样的标记:
|
|||||||
#endif /* CONFIG_SOMETHING */
|
#endif /* CONFIG_SOMETHING */
|
||||||
|
|
||||||
|
|
||||||
附录 I) 参考
|
附录 I) 参考资料
|
||||||
-------------------
|
----------------
|
||||||
|
|
||||||
The C Programming Language, 第二版
|
The C Programming Language, 2nd Edition
|
||||||
作者:Brian W. Kernighan 和 Denni M. Ritchie.
|
作者:Brian W. Kernighan 和 Denni M. Ritchie.
|
||||||
Prentice Hall, Inc., 1988.
|
Prentice Hall, Inc., 1988.
|
||||||
ISBN 0-13-110362-8 (软皮), 0-13-110370-9 (硬皮).
|
ISBN 0-13-110362-8 (平装), 0-13-110370-9 (精装).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
《C程序设计语言(第2版)》
|
||||||
|
作者:[美] Brian W. Kernighan / [美] Dennis M. Ritchie
|
||||||
|
译者:徐宝文 / 李志 / 尤晋元(审校)
|
||||||
|
出版社:机械工业出版社,2019
|
||||||
|
ISBN:9787111617945
|
||||||
|
|
||||||
The Practice of Programming
|
The Practice of Programming
|
||||||
作者:Brian W. Kernighan 和 Rob Pike.
|
作者:Brian W. Kernighan 和 Rob Pike.
|
||||||
Addison-Wesley, Inc., 1999.
|
Addison-Wesley, Inc., 1999.
|
||||||
ISBN 0-201-61586-X.
|
ISBN 0-201-61586-X.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
《程序设计实践》
|
||||||
|
作者:[美] Brian W. Kernighan / [美] Rob Pike
|
||||||
|
出版社:机械工业出版社,2005
|
||||||
|
ISBN:9787111091578
|
||||||
|
|
||||||
|
《程序设计实践》
|
||||||
|
作者:[美] Brian W. Kernighan / Rob Pike
|
||||||
|
译者:裘宗燕
|
||||||
|
出版社:机械工业出版社,2000
|
||||||
|
ISBN:9787111075738
|
||||||
|
|
||||||
GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
|
GNU 手册 - 遵循 K&R 标准和此文本 - cpp, gcc, gcc internals and indent,
|
||||||
都可以从 https://www.gnu.org/manual/ 找到
|
都可以从 https://www.gnu.org/manual/ 找到
|
||||||
|
|
||||||
WG14 是 C 语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
|
WG14 是 C 语言的国际标准化工作组,URL: http://www.open-std.org/JTC1/SC22/WG14/
|
||||||
|
|
||||||
Kernel process/coding-style.rst,作者 greg@kroah.com 发表于 OLS 2002:
|
内核文档 Documentation/process/coding-style.rst,
|
||||||
|
作者 greg@kroah.com 发表于 OLS 2002:
|
||||||
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
|
http://www.kroah.com/linux/talks/ols_2002_kernel_codingstyle_talk/html/
|
||||||
|
@ -1,17 +1,20 @@
|
|||||||
.. _cn_email_clients:
|
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
.. include:: ../disclaimer-zh_CN.rst
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
:Original: :ref:`Documentation/process/email-clients.rst <email_clients>`
|
.. _cn_email_clients:
|
||||||
|
|
||||||
译者::
|
:Original: Documentation/process/email-clients.rst
|
||||||
|
|
||||||
中文版维护者: 贾威威 Harry Wei <harryxiyou@gmail.com>
|
:译者:
|
||||||
中文版翻译者: 贾威威 Harry Wei <harryxiyou@gmail.com>
|
- 贾威威 Harry Wei <harryxiyou@gmail.com>
|
||||||
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
|
- 时奎亮 Alex Shi <alexs@kernel.org>
|
||||||
中文版校译者: Yinglin Luan <synmyth@gmail.com>
|
- 吴想成 Wu XiangCheng <bobwxc@email.cn>
|
||||||
Xiaochen Wang <wangxiaochen0@gmail.com>
|
|
||||||
yaxinsn <yaxinsn@163.com>
|
:校译:
|
||||||
|
- Yinglin Luan <synmyth@gmail.com>
|
||||||
|
- Xiaochen Wang <wangxiaochen0@gmail.com>
|
||||||
|
- yaxinsn <yaxinsn@163.com>
|
||||||
|
|
||||||
Linux邮件客户端配置信息
|
Linux邮件客户端配置信息
|
||||||
=======================
|
=======================
|
||||||
@ -27,12 +30,17 @@ Git
|
|||||||
改日志。如果工作正常,再将补丁发送到相应的邮件列表。
|
改日志。如果工作正常,再将补丁发送到相应的邮件列表。
|
||||||
|
|
||||||
|
|
||||||
普通配置
|
通用配置
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的内嵌文本。有些维护者
|
Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的内嵌文本。有些维护者
|
||||||
接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的,
|
接收附件,但是附件的内容格式应该是"text/plain"。然而,附件一般是不赞成的,
|
||||||
因为这会使补丁的引用部分在评论过程中变的很困难。
|
因为这会使补丁的引用部分在评论过程中变的很困难。
|
||||||
|
|
||||||
|
同时也强烈建议在补丁或其他邮件的正文中使用纯文本格式。https://useplaintext.email
|
||||||
|
有助于了解如何配置你喜欢的邮件客户端,并在您还没有首选的情况下列出一些推荐的
|
||||||
|
客户端。
|
||||||
|
|
||||||
用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如,
|
用来发送Linux内核补丁的邮件客户端在发送补丁时应该处于文本的原始状态。例如,
|
||||||
他们不能改变或者删除制表符或者空格,甚至是在每一行的开头或者结尾。
|
他们不能改变或者删除制表符或者空格,甚至是在每一行的开头或者结尾。
|
||||||
|
|
||||||
@ -40,17 +48,17 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
|
|||||||
|
|
||||||
不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。
|
不要让你的邮件客户端进行自动换行。这样也会破坏你的补丁。
|
||||||
|
|
||||||
邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码方式,
|
邮件客户端不能改变文本的字符集编码方式。要发送的补丁只能是ASCII或者UTF-8编码
|
||||||
如果你使用UTF-8编码方式发送邮件,那么你将会避免一些可能发生的字符集问题。
|
方式,如果你使用UTF-8编码方式发送邮件,那么你将会避免一些可能发生的字符集问题。
|
||||||
|
|
||||||
邮件客户端应该形成并且保持 References: 或者 In-Reply-To: 标题,那么
|
邮件客户端应该生成并且保持“References:”或者“In-Reply-To:”邮件头,这样邮件会话
|
||||||
邮件话题就不会中断。
|
就不会中断。
|
||||||
|
|
||||||
复制粘帖(或者剪贴粘帖)通常不能用于补丁,因为制表符会转换为空格。使用xclipboard, xclip
|
复制粘帖(或者剪贴粘帖)通常不能用于补丁,因为制表符会转换为空格。使用xclipboard,
|
||||||
或者xcutsel也许可以,但是最好测试一下或者避免使用复制粘帖。
|
xclip或者xcutsel也许可以,但是最好测试一下或者避免使用复制粘帖。
|
||||||
|
|
||||||
不要在使用PGP/GPG署名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的补丁。
|
不要在使用PGP/GPG签名的邮件中包含补丁。这样会使得很多脚本不能读取和适用于你的
|
||||||
(这个问题应该是可以修复的)
|
补丁。(这个问题应该是可以修复的)
|
||||||
|
|
||||||
在给内核邮件列表发送补丁之前,给自己发送一个补丁是个不错的主意,保存接收到的
|
在给内核邮件列表发送补丁之前,给自己发送一个补丁是个不错的主意,保存接收到的
|
||||||
邮件,将补丁用'patch'命令打上,如果成功了,再给内核邮件列表发送。
|
邮件,将补丁用'patch'命令打上,如果成功了,再给内核邮件列表发送。
|
||||||
@ -58,98 +66,133 @@ Linux内核补丁是通过邮件被提交的,最好把补丁作为邮件体的
|
|||||||
|
|
||||||
一些邮件客户端提示
|
一些邮件客户端提示
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
这里给出一些详细的MUA配置提示,可以用于给Linux内核发送补丁。这些并不意味是
|
这里给出一些详细的MUA配置提示,可以用于给Linux内核发送补丁。这些并不意味是
|
||||||
所有的软件包配置总结。
|
所有的软件包配置总结。
|
||||||
|
|
||||||
说明:
|
说明:
|
||||||
TUI = 以文本为基础的用户接口
|
|
||||||
GUI = 图形界面用户接口
|
- TUI = 以文本为基础的用户接口
|
||||||
|
- GUI = 图形界面用户接口
|
||||||
|
|
||||||
Alpine (TUI)
|
Alpine (TUI)
|
||||||
~~~~~~~~~~~~
|
************
|
||||||
|
|
||||||
配置选项:
|
配置选项:
|
||||||
在"Sending Preferences"部分:
|
|
||||||
|
|
||||||
- "Do Not Send Flowed Text"必须开启
|
在 :menuselection:`Sending Preferences` 菜单:
|
||||||
- "Strip Whitespace Before Sending"必须关闭
|
|
||||||
|
|
||||||
当写邮件时,光标应该放在补丁会出现的地方,然后按下CTRL-R组合键,使指定的
|
- :menuselection:`Do Not Send Flowed Text` 必须开启
|
||||||
补丁文件嵌入到邮件中。
|
- :menuselection:`Strip Whitespace Before Sending` 必须关闭
|
||||||
|
|
||||||
|
当写邮件时,光标应该放在补丁会出现的地方,然后按下 :kbd:`CTRL-R` 组合键,使指
|
||||||
|
定的补丁文件嵌入到邮件中。
|
||||||
|
|
||||||
|
Claws Mail (GUI)
|
||||||
|
****************
|
||||||
|
|
||||||
|
可以用,有人用它成功地发过补丁。
|
||||||
|
|
||||||
|
用 :menuselection:`Message-->Insert File` (:kbd:`CTRL-I`) 或外置编辑器插入补丁。
|
||||||
|
|
||||||
|
若要在Claws编辑窗口重修改插入的补丁,需关闭
|
||||||
|
:menuselection:`Configuration-->Preferences-->Compose-->Wrapping`
|
||||||
|
的 `Auto wrapping` 。
|
||||||
|
|
||||||
Evolution (GUI)
|
Evolution (GUI)
|
||||||
~~~~~~~~~~~~~~~
|
***************
|
||||||
|
|
||||||
一些开发者成功的使用它发送补丁
|
|
||||||
|
|
||||||
当选择邮件选项:Preformat
|
|
||||||
从Format->Heading->Preformatted (Ctrl-7)或者工具栏
|
|
||||||
|
|
||||||
然后使用:
|
|
||||||
Insert->Text File... (Alt-n x)插入补丁文件。
|
|
||||||
|
|
||||||
你还可以"diff -Nru old.c new.c | xclip",选择Preformat,然后使用中间键进行粘帖。
|
|
||||||
|
|
||||||
Kmail (GUI)
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
一些开发者成功的使用它发送补丁。
|
一些开发者成功的使用它发送补丁。
|
||||||
|
|
||||||
默认设置不为HTML格式是合适的;不要启用它。
|
撰写邮件时:
|
||||||
|
从 :menuselection:`格式-->段落样式-->预格式化` (:kbd:`CTRL-7`)
|
||||||
|
或工具栏选择 :menuselection:`预格式化` ;
|
||||||
|
|
||||||
当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输入的任何文本
|
然后使用:
|
||||||
都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法就是启用自动换行来书写邮件,
|
:menuselection:`插入-->文本文件...` (:kbd:`ALT-N x`) 插入补丁文件。
|
||||||
然后把它保存为草稿。一旦你在草稿中再次打开它,它已经全部自动换行了,那么你的邮件虽然没有
|
|
||||||
选择自动换行,但是还不会失去已有的自动换行。
|
|
||||||
|
|
||||||
在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字号(---)。
|
你还可以 ``diff -Nru old.c new.c | xclip`` ,选择 :menuselection:`预格式化` ,
|
||||||
|
然后使用鼠标中键进行粘帖。
|
||||||
|
|
||||||
然后在"Message"菜单条目,选择插入文件,接着选取你的补丁文件。还有一个额外的选项,你可以
|
Kmail (GUI)
|
||||||
通过它配置你的邮件建立工具栏菜单,还可以带上"insert file"图标。
|
***********
|
||||||
|
|
||||||
你可以安全地通过GPG标记附件,但是内嵌补丁最好不要使用GPG标记它们。作为内嵌文本的签发补丁,
|
一些开发者成功的使用它发送补丁。
|
||||||
当从GPG中提取7位编码时会使他们变的更加复杂。
|
|
||||||
|
|
||||||
如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选中属性,突出"Suggest automatic
|
默认撰写设置禁用HTML格式是合适的;不要启用它。
|
||||||
display",这样内嵌附件更容易让读者看到。
|
|
||||||
|
|
||||||
当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然后右击选择
|
当书写一封邮件的时候,在选项下面不要选择自动换行。唯一的缺点就是你在邮件中输
|
||||||
"save as"。你可以使用一个没有更改的包含补丁的邮件,如果它是以正确的形式组成。当你正真在它
|
入的任何文本都不会被自动换行,因此你必须在发送补丁之前手动换行。最简单的方法
|
||||||
自己的窗口之下察看,那时没有选项可以保存邮件--已经有一个这样的bug被汇报到了kmail的bugzilla
|
就是启用自动换行来书写邮件,然后把它保存为草稿。一旦你在草稿中再次打开它,它
|
||||||
并且希望这将会被处理。邮件是以只针对某个用户可读写的权限被保存的,所以如果你想把邮件复制到其他地方,
|
已经全部自动换行了,那么你的邮件虽然没有选择自动换行,但是还不会失去已有的自
|
||||||
你不得不把他们的权限改为组或者整体可读。
|
动换行。
|
||||||
|
|
||||||
|
在邮件的底部,插入补丁之前,放上常用的补丁定界符:三个连字符(``---``)。
|
||||||
|
|
||||||
|
然后在 :menuselection:`信件` 菜单,选择 :menuselection:`插入文本文件` ,接
|
||||||
|
着选取你的补丁文件。还有一个额外的选项,你可以通过它配置你的创建新邮件工具栏,
|
||||||
|
加上 :menuselection:`插入文本文件` 图标。
|
||||||
|
|
||||||
|
将编辑器窗口拉到足够宽避免折行。对于KMail 1.13.5 (KDE 4.5.4),它会在发送邮件
|
||||||
|
时对编辑器窗口中显示折行的地方自动换行。在选项菜单中取消自动换行仍不能解决。
|
||||||
|
因此,如果你的补丁中有非常长的行,必须在发送之前把编辑器窗口拉得非常宽。
|
||||||
|
参见:https://bugs.kde.org/show_bug.cgi?id=174034
|
||||||
|
|
||||||
|
你可以安全地用GPG签名附件,但是内嵌补丁最好不要使用GPG签名它们。作为内嵌文本
|
||||||
|
插入的签名补丁将使其难以从7-bit编码中提取。
|
||||||
|
|
||||||
|
如果你非要以附件的形式发送补丁,那么就右键点击附件,然后选择
|
||||||
|
:menuselection:`属性` ,打开 :menuselection:`建议自动显示` ,使附件内联更容
|
||||||
|
易让读者看到。
|
||||||
|
|
||||||
|
当你要保存将要发送的内嵌文本补丁,你可以从消息列表窗格选择包含补丁的邮件,然
|
||||||
|
后右键选择 :menuselection:`另存为` 。如果整个电子邮件的组成正确,您可直接将
|
||||||
|
其作为补丁使用。电子邮件以当前用户可读写权限保存,因此您必须 ``chmod`` ,以
|
||||||
|
使其在复制到别处时用户组和其他人可读。
|
||||||
|
|
||||||
Lotus Notes (GUI)
|
Lotus Notes (GUI)
|
||||||
~~~~~~~~~~~~~~~~~
|
*****************
|
||||||
|
|
||||||
不要使用它。
|
不要使用它。
|
||||||
|
|
||||||
|
IBM Verse (Web GUI)
|
||||||
|
*******************
|
||||||
|
|
||||||
|
同上条。
|
||||||
|
|
||||||
Mutt (TUI)
|
Mutt (TUI)
|
||||||
~~~~~~~~~~
|
**********
|
||||||
|
|
||||||
很多Linux开发人员使用mutt客户端,所以证明它肯定工作的非常漂亮。
|
很多Linux开发人员使用mutt客户端,这证明它肯定工作得非常漂亮。
|
||||||
|
|
||||||
Mutt不自带编辑器,所以不管你使用什么编辑器都不应该带有自动断行。大多数编辑器都带有
|
Mutt不自带编辑器,所以不管你使用什么编辑器,不自动断行就行。大多数编辑器都有
|
||||||
一个"insert file"选项,它可以通过不改变文件内容的方式插入文件。
|
:menuselection:`插入文件` 选项,它可以在不改变文件内容的情况下插入文件。
|
||||||
|
|
||||||
|
用 ``vim`` 作为mutt的编辑器::
|
||||||
|
|
||||||
'vim'作为mutt的编辑器:
|
|
||||||
set editor="vi"
|
set editor="vi"
|
||||||
|
|
||||||
如果使用xclip,敲入以下命令
|
如果使用xclip,敲入以下命令::
|
||||||
|
|
||||||
:set paste
|
:set paste
|
||||||
按中键之前或者shift-insert或者使用
|
|
||||||
|
然后再按中键或者shift-insert或者使用::
|
||||||
|
|
||||||
:r filename
|
:r filename
|
||||||
|
|
||||||
如果想要把补丁作为内嵌文本。
|
把补丁插入为内嵌文本。
|
||||||
(a)ttach工作的很好,不带有"set paste"。
|
在未设置 ``set paste`` 时(a)ttach工作的很好。
|
||||||
|
|
||||||
你可以通过 ``git format-patch`` 生成补丁,然后用 Mutt发送它们::
|
你可以通过 ``git format-patch`` 生成补丁,然后用 Mutt发送它们::
|
||||||
|
|
||||||
$ mutt -H 0001-some-bug-fix.patch
|
$ mutt -H 0001-some-bug-fix.patch
|
||||||
|
|
||||||
配置选项:
|
配置选项:
|
||||||
|
|
||||||
它应该以默认设置的形式工作。
|
它应该以默认设置的形式工作。
|
||||||
然而,把"send_charset"设置为"us-ascii::utf-8"也是一个不错的主意。
|
然而,把 ``send_charset`` 设置一下也是一个不错的主意::
|
||||||
|
|
||||||
|
set send_charset="us-ascii:utf-8"
|
||||||
|
|
||||||
Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置::
|
Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁的最小配置::
|
||||||
|
|
||||||
@ -178,71 +221,107 @@ Mutt 是高度可配置的。 这里是个使用mutt通过 Gmail 发送的补丁
|
|||||||
set from = "username@gmail.com"
|
set from = "username@gmail.com"
|
||||||
set use_from = yes
|
set use_from = yes
|
||||||
|
|
||||||
Mutt文档含有更多信息:
|
Mutt文档含有更多信息:
|
||||||
|
|
||||||
http://dev.mutt.org/trac/wiki/UseCases/Gmail
|
https://gitlab.com/muttmua/mutt/-/wikis/UseCases/Gmail
|
||||||
|
|
||||||
http://dev.mutt.org/doc/manual.html
|
http://www.mutt.org/doc/manual/
|
||||||
|
|
||||||
Pine (TUI)
|
Pine (TUI)
|
||||||
~~~~~~~~~~
|
**********
|
||||||
|
|
||||||
Pine过去有一些空格删减问题,但是这些现在应该都被修复了。
|
Pine过去有一些空格删减问题,但是这些现在应该都被修复了。
|
||||||
|
|
||||||
如果可以,请使用alpine(pine的继承者)
|
如果可以,请使用alpine(pine的继承者)。
|
||||||
|
|
||||||
配置选项:
|
配置选项:
|
||||||
- 最近的版本需要消除流程文本
|
|
||||||
- "no-strip-whitespace-before-send"选项也是需要的。
|
- 最近的版本需要 ``quell-flowed-text``
|
||||||
|
- ``no-strip-whitespace-before-send`` 选项也是需要的。
|
||||||
|
|
||||||
|
|
||||||
Sylpheed (GUI)
|
Sylpheed (GUI)
|
||||||
~~~~~~~~~~~~~~
|
**************
|
||||||
|
|
||||||
- 内嵌文本可以很好的工作(或者使用附件)。
|
- 内嵌文本可以很好的工作(或者使用附件)。
|
||||||
- 允许使用外部的编辑器。
|
- 允许使用外部的编辑器。
|
||||||
- 对于目录较多时非常慢。
|
- 收件箱较多时非常慢。
|
||||||
- 如果通过non-SSL连接,无法使用TLS SMTP授权。
|
- 如果通过non-SSL连接,无法使用TLS SMTP授权。
|
||||||
- 在组成窗口中有一个很有用的ruler bar。
|
- 撰写窗口的标尺很有用。
|
||||||
- 给地址本中添加地址就不会正确的了解显示名。
|
- 将地址添加到通讯簿时无法正确理解显示的名称。
|
||||||
|
|
||||||
Thunderbird (GUI)
|
Thunderbird (GUI)
|
||||||
~~~~~~~~~~~~~~~~~
|
*****************
|
||||||
|
|
||||||
默认情况下,thunderbird很容易损坏文本,但是还有一些方法可以强制它变得更好。
|
Thunderbird是Outlook的克隆版本,它很容易损坏文本,但也有一些方法强制修正。
|
||||||
|
|
||||||
- 在用户帐号设置里,组成和寻址,不要选择"Compose messages in HTML format"。
|
在完成修改后(包括安装扩展),您需要重新启动Thunderbird。
|
||||||
|
|
||||||
- 编辑你的Thunderbird配置设置来使它不要拆行使用:user_pref("mailnews.wraplength", 0);
|
- 允许使用外部编辑器:
|
||||||
|
|
||||||
- 编辑你的Thunderbird配置设置,使它不要使用"format=flowed"格式:user_pref("mailnews.
|
使用Thunderbird发补丁最简单的方法是使用扩展来打开您最喜欢的外部编辑器。
|
||||||
send_plaintext_flowed", false);
|
|
||||||
|
|
||||||
- 你需要使Thunderbird变为预先格式方式:
|
下面是一些能够做到这一点的扩展样例。
|
||||||
如果默认情况下你书写的是HTML格式,那不是很难。仅仅从标题栏的下拉框中选择"Preformat"格式。
|
|
||||||
如果默认情况下你书写的是文本格式,你不得把它改为HTML格式(仅仅作为一次性的)来书写新的消息,
|
|
||||||
然后强制使它回到文本格式,否则它就会拆行。要实现它,在写信的图标上使用shift键来使它变为HTML
|
|
||||||
格式,然后标题栏的下拉框中选择"Preformat"格式。
|
|
||||||
|
|
||||||
- 允许使用外部的编辑器:
|
- “External Editor Revived”
|
||||||
针对Thunderbird打补丁最简单的方法就是使用一个"external editor"扩展,然后使用你最喜欢的
|
|
||||||
$EDITOR来读取或者合并补丁到文本中。要实现它,可以下载并且安装这个扩展,然后添加一个使用它的
|
https://github.com/Frederick888/external-editor-revived
|
||||||
按键View->Toolbars->Customize...最后当你书写信息的时候仅仅点击它就可以了。
|
|
||||||
|
https://addons.thunderbird.net/en-GB/thunderbird/addon/external-editor-revived/
|
||||||
|
|
||||||
|
它需要安装“本地消息主机(native messaging host)”。
|
||||||
|
参见以下文档:
|
||||||
|
https://github.com/Frederick888/external-editor-revived/wiki
|
||||||
|
|
||||||
|
- “External Editor”
|
||||||
|
|
||||||
|
https://github.com/exteditor/exteditor
|
||||||
|
|
||||||
|
下载并安装此扩展,然后打开 :menuselection:`新建消息` 窗口, 用
|
||||||
|
:menuselection:`查看-->工具栏-->自定义...` 给它增加一个按钮,直接点击此
|
||||||
|
按钮即可使用外置编辑器。
|
||||||
|
|
||||||
|
请注意,“External Editor”要求你的编辑器不能fork,换句话说,编辑器必须在
|
||||||
|
关闭前不返回。你可能需要传递额外的参数或修改编辑器设置。最值得注意的是,
|
||||||
|
如果您使用的是gvim,那么您必须将 :menuselection:`external editor` 设置的
|
||||||
|
编辑器字段设置为 ``/usr/bin/gvim --nofork"`` (假设可执行文件在
|
||||||
|
``/usr/bin`` ),以传递 ``-f`` 参数。如果您正在使用其他编辑器,请阅读其
|
||||||
|
手册了解如何处理。
|
||||||
|
|
||||||
|
若要修正内部编辑器,请执行以下操作:
|
||||||
|
|
||||||
|
- 修改你的Thunderbird设置,不要使用 ``format=flowed`` !
|
||||||
|
回到主窗口,按照
|
||||||
|
:menuselection:`主菜单-->首选项-->常规-->配置编辑器...`
|
||||||
|
打开Thunderbird的配置编辑器。
|
||||||
|
|
||||||
|
- 将 ``mailnews.send_plaintext_flowed`` 设为 ``false``
|
||||||
|
|
||||||
|
- 将 ``mailnews.wraplength`` 从 ``72`` 改为 ``0``
|
||||||
|
|
||||||
|
- 不要写HTML邮件!
|
||||||
|
回到主窗口,打开
|
||||||
|
:menuselection:`主菜单-->账户设置-->你的@邮件.地址-->通讯录/编写&地址簿` ,
|
||||||
|
关掉 ``以HTML格式编写消息`` 。
|
||||||
|
|
||||||
|
- 只用纯文本格式查看邮件!
|
||||||
|
回到主窗口, :menuselection:`主菜单-->查看-->消息体为-->纯文本` !
|
||||||
|
|
||||||
TkRat (GUI)
|
TkRat (GUI)
|
||||||
~~~~~~~~~~~
|
***********
|
||||||
|
|
||||||
可以使用它。使用"Insert file..."或者外部的编辑器。
|
可以使用它。使用"Insert file..."或者外部的编辑器。
|
||||||
|
|
||||||
Gmail (Web GUI)
|
Gmail (Web GUI)
|
||||||
~~~~~~~~~~~~~~~
|
***************
|
||||||
|
|
||||||
不要使用它发送补丁。
|
不要使用它发送补丁。
|
||||||
|
|
||||||
Gmail网页客户端自动地把制表符转换为空格。
|
Gmail网页客户端自动地把制表符转换为空格。
|
||||||
|
|
||||||
虽然制表符转换为空格问题可以被外部编辑器解决,同时它还会使用回车换行把每行拆分为78个字符。
|
虽然制表符转换为空格问题可以被外部编辑器解决,但它同时还会使用回车换行把每行
|
||||||
|
拆分为78个字符。
|
||||||
|
|
||||||
另一个问题是Gmail还会把任何不是ASCII的字符的信息改为base64编码。它把东西变的像欧洲人的名字。
|
另一个问题是Gmail还会把任何含有非ASCII的字符的消息改用base64编码,如欧洲人的
|
||||||
|
名字。
|
||||||
|
|
||||||
###
|
|
||||||
|
@ -1,105 +1,111 @@
|
|||||||
.. include:: ../disclaimer-zh_CN.rst
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
:Original: :ref:`Documentation/process/submit-checklist.rst <submitchecklist>`
|
:Original: Documentation/process/submit-checklist.rst
|
||||||
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
|
:Translator:
|
||||||
|
- Alex Shi <alexs@kernel.org>
|
||||||
|
- Wu XiangCheng <bobwxc@email.cn>
|
||||||
|
|
||||||
.. _cn_submitchecklist:
|
.. _cn_submitchecklist:
|
||||||
|
|
||||||
Linux内核补丁提交清单
|
Linux内核补丁提交检查单
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
如果开发人员希望看到他们的内核补丁提交更快地被接受,那么他们应该做一些基本
|
如果开发人员希望看到他们的内核补丁提交更快地被接受,那么他们应该做一些基本
|
||||||
的事情。
|
的事情。
|
||||||
|
|
||||||
这些都是在
|
这些都是在 Documentation/translations/zh_CN/process/submitting-patches.rst
|
||||||
:ref:`Documentation/translations/zh_CN/process/submitting-patches.rst <cn_submittingpatches>`
|
|
||||||
和其他有关提交Linux内核补丁的文档中提供的。
|
和其他有关提交Linux内核补丁的文档中提供的。
|
||||||
|
|
||||||
1) 如果使用工具,则包括定义/声明该工具的文件。不要依赖于其他头文件拉入您使用
|
1) 如果使用工具,则包括定义/声明该工具的文件。不要依赖其他头文件来引入您使用
|
||||||
的头文件。
|
的头文件。
|
||||||
|
|
||||||
2) 干净的编译:
|
2) 干净的编译:
|
||||||
|
|
||||||
a) 使用适用或修改的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有GCC
|
a) 使用合适的 ``CONFIG`` 选项 ``=y``、``=m`` 和 ``=n`` 。没有 ``gcc``
|
||||||
警告/错误,没有链接器警告/错误。
|
警告/错误,没有链接器警告/错误。
|
||||||
|
|
||||||
b) 通过allnoconfig、allmodconfig
|
b) 通过 ``allnoconfig`` 、 ``allmodconfig``
|
||||||
|
|
||||||
c) 使用 ``O=builddir`` 时可以成功编译
|
c) 使用 ``O=builddir`` 时可以成功编译
|
||||||
|
|
||||||
3) 通过使用本地交叉编译工具或其他一些构建场在多个CPU体系结构上构建。
|
d) 任何 Doucmentation/ 下的变更都能成功构建且不引入新警告/错误。
|
||||||
|
用 ``make htmldocs`` 或 ``make pdfdocs`` 检验构建情况并修复问题。
|
||||||
|
|
||||||
|
3) 通过使用本地交叉编译工具或其他一些构建设施在多个CPU体系结构上构建。
|
||||||
|
|
||||||
4) PPC64是一种很好的交叉编译检查体系结构,因为它倾向于对64位的数使用无符号
|
4) PPC64是一种很好的交叉编译检查体系结构,因为它倾向于对64位的数使用无符号
|
||||||
长整型。
|
长整型。
|
||||||
|
|
||||||
5) 如下所述 :ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`.
|
5) 按 Documentation/translations/zh_CN/process/coding-style.rst 所述检查您的
|
||||||
检查您的补丁是否为常规样式。在提交( ``scripts/check patch.pl`` )之前,
|
补丁是否为常规样式。在提交之前使用补丁样式检查器 ``scripts/checkpatch.pl``
|
||||||
使用补丁样式检查器检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
|
检查是否有轻微的冲突。您应该能够处理您的补丁中存在的所有
|
||||||
违规行为。
|
违规行为。
|
||||||
|
|
||||||
6) 任何新的或修改过的 ``CONFIG`` 选项都不会弄脏配置菜单,并默认为关闭,除非
|
6) 任何新的或修改过的 ``CONFIG`` 选项都不应搞乱配置菜单,并默认为关闭,除非
|
||||||
它们符合 ``Documentation/kbuild/kconfig-language.rst`` 中记录的异常条件,
|
它们符合 ``Documentation/kbuild/kconfig-language.rst`` 菜单属性:默认值中
|
||||||
菜单属性:默认值.
|
记录的例外条件。
|
||||||
|
|
||||||
7) 所有新的 ``kconfig`` 选项都有帮助文本。
|
7) 所有新的 ``kconfig`` 选项都有帮助文本。
|
||||||
|
|
||||||
8) 已仔细审查了相关的 ``Kconfig`` 组合。这很难用测试来纠正——脑力在这里是有
|
8) 已仔细审查了相关的 ``Kconfig`` 组合。这很难用测试来纠正——脑力在这里是有
|
||||||
回报的。
|
回报的。
|
||||||
|
|
||||||
9) 用 sparse 检查干净。
|
9) 通过 sparse 清查。
|
||||||
|
(参见 Documentation/translations/zh_CN/dev-tools/sparse.rst )
|
||||||
|
|
||||||
10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何
|
10) 使用 ``make checkstack`` 和 ``make namespacecheck`` 并修复他们发现的任何
|
||||||
问题。
|
问题。
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
``checkstack`` 并没有明确指出问题,但是任何一个在堆栈上使用超过512
|
``checkstack`` 并不会明确指出问题,但是任何一个在堆栈上使用超过512
|
||||||
字节的函数都可以进行更改。
|
字节的函数都可以进行更改。
|
||||||
|
|
||||||
11) 包括 :ref:`kernel-doc <kernel_doc>` 内核文档以记录全局内核API。(静态函数
|
11) 包括 :ref:`kernel-doc <kernel_doc_zh>` 内核文档以记录全局内核API。(静态
|
||||||
不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
|
函数不需要,但也可以。)使用 ``make htmldocs`` 或 ``make pdfdocs`` 检查
|
||||||
:ref:`kernel-doc <kernel_doc>` 并修复任何问题。
|
:ref:`kernel-doc <kernel_doc_zh>` 并修复任何问题。
|
||||||
|
|
||||||
12) 通过以下选项同时启用的测试 ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
|
12) 通过以下选项同时启用的测试: ``CONFIG_PREEMPT``, ``CONFIG_DEBUG_PREEMPT``,
|
||||||
``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
|
``CONFIG_DEBUG_SLAB``, ``CONFIG_DEBUG_PAGEALLOC``, ``CONFIG_DEBUG_MUTEXES``,
|
||||||
``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
|
``CONFIG_DEBUG_SPINLOCK``, ``CONFIG_DEBUG_ATOMIC_SLEEP``,
|
||||||
``CONFIG_PROVE_RCU`` and ``CONFIG_DEBUG_OBJECTS_RCU_HEAD``
|
``CONFIG_PROVE_RCU`` 和 ``CONFIG_DEBUG_OBJECTS_RCU_HEAD`` 。
|
||||||
|
|
||||||
13) 已经过构建和运行时测试,包括有或没有 ``CONFIG_SMP``, ``CONFIG_PREEMPT``.
|
13) 在 ``CONFIG_SMP``, ``CONFIG_PREEMPT`` 开启和关闭的情况下都进行构建和运行
|
||||||
|
时测试。
|
||||||
|
|
||||||
14) 如果补丁程序影响IO/磁盘等:使用或不使用 ``CONFIG_LBDAF`` 进行测试。
|
14) 所有代码路径都已在启用所有死锁检测(lockdep)功能的情况下运行。
|
||||||
|
|
||||||
15) 所有代码路径都已在启用所有lockdep功能的情况下运行。
|
15) 所有新的 ``/proc`` 条目都记录在 ``Documentation/``
|
||||||
|
|
||||||
16) 所有新的/proc条目都记录在 ``Documentation/``
|
16) 所有新的内核引导参数都记录在
|
||||||
|
|
||||||
17) 所有新的内核引导参数都记录在
|
|
||||||
Documentation/admin-guide/kernel-parameters.rst 中。
|
Documentation/admin-guide/kernel-parameters.rst 中。
|
||||||
|
|
||||||
18) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``
|
17) 所有新的模块参数都记录在 ``MODULE_PARM_DESC()``
|
||||||
|
|
||||||
19) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息,
|
18) 所有新的用户空间接口都记录在 ``Documentation/ABI/`` 中。有关详细信息,
|
||||||
请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送
|
请参阅 ``Documentation/ABI/README`` 。更改用户空间接口的补丁应该抄送
|
||||||
linux-api@vger.kernel.org。
|
linux-api@vger.kernel.org。
|
||||||
|
|
||||||
20) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/``
|
19) 已通过至少注入slab和page分配失败进行检查。请参阅 ``Documentation/fault-injection/`` 。
|
||||||
如果新代码是实质性的,那么添加子系统特定的故障注入可能是合适的。
|
如果新代码是实质性的,那么添加子系统特定的故障注入可能是合适的。
|
||||||
|
|
||||||
21) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这
|
20) 新添加的代码已经用 ``gcc -W`` 编译(使用 ``make EXTRA-CFLAGS=-W`` )。这
|
||||||
将产生大量噪声,但对于查找诸如“警告:有符号和无符号之间的比较”之类的错误
|
将产生大量噪声,但对于查找诸如“警告:有符号和无符号之间的比较”之类的错误
|
||||||
很有用。
|
很有用。
|
||||||
|
|
||||||
22) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以
|
21) 在它被合并到-mm补丁集中之后进行测试,以确保它仍然与所有其他排队的补丁以
|
||||||
及VM、VFS和其他子系统中的各种更改一起工作。
|
及VM、VFS和其他子系统中的各种更改一起工作。
|
||||||
|
|
||||||
23) 所有内存屏障例如 ``barrier()``, ``rmb()``, ``wmb()`` 都需要源代码中的注
|
22) 所有内存屏障(例如 ``barrier()``, ``rmb()``, ``wmb()`` )都需要源代码注
|
||||||
释来解释它们正在执行的操作及其原因的逻辑。
|
释来解释它们正在执行的操作及其原因的逻辑。
|
||||||
|
|
||||||
24) 如果补丁添加了任何ioctl,那么也要更新 ``Documentation/userspace-api/ioctl/ioctl-number.rst``
|
23) 如果补丁添加了任何ioctl,那么也要更新
|
||||||
|
``Documentation/userspace-api/ioctl/ioctl-number.rst`` 。
|
||||||
|
|
||||||
25) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
|
24) 如果修改后的源代码依赖或使用与以下 ``Kconfig`` 符号相关的任何内核API或
|
||||||
功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况
|
功能,则在禁用相关 ``Kconfig`` 符号和/或 ``=m`` (如果该选项可用)的情况
|
||||||
下测试以下多个构建[并非所有这些都同时存在,只是它们的各种/随机组合]:
|
下测试以下多个构建[并非所有这些都同时存在,只是它们的各种/随机组合]:
|
||||||
|
|
||||||
``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``, ``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
|
``CONFIG_SMP``, ``CONFIG_SYSFS``, ``CONFIG_PROC_FS``, ``CONFIG_INPUT``,
|
||||||
``CONFIG_NET``, ``CONFIG_INET=n`` (但是后者伴随 ``CONFIG_NET=y``).
|
``CONFIG_PCI``, ``CONFIG_BLOCK``, ``CONFIG_PM``, ``CONFIG_MAGIC_SYSRQ``,
|
||||||
|
``CONFIG_NET``, ``CONFIG_INET=n`` (但是最后一个需要 ``CONFIG_NET=y`` )。
|
||||||
|
@ -1,142 +1,92 @@
|
|||||||
.. _cn_submittingpatches:
|
.. SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
.. include:: ../disclaimer-zh_CN.rst
|
.. include:: ../disclaimer-zh_CN.rst
|
||||||
|
|
||||||
:Original: :ref:`Documentation/process/submitting-patches.rst <submittingpatches>`
|
.. _cn_submittingpatches:
|
||||||
|
|
||||||
译者::
|
:Original: Documentation/process/submitting-patches.rst
|
||||||
|
|
||||||
中文版维护者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
|
:译者:
|
||||||
中文版翻译者: 钟宇 TripleX Chung <xxx.phy@gmail.com>
|
- 钟宇 TripleX Chung <xxx.phy@gmail.com>
|
||||||
时奎亮 Alex Shi <alex.shi@linux.alibaba.com>
|
- 时奎亮 Alex Shi <alexs@kernel.org>
|
||||||
中文版校译者: 李阳 Li Yang <leoyang.li@nxp.com>
|
- 吴想成 Wu XiangCheng <bobwxc@email.cn>
|
||||||
王聪 Wang Cong <xiyou.wangcong@gmail.com>
|
|
||||||
|
:校译:
|
||||||
|
- 李阳 Li Yang <leoyang.li@nxp.com>
|
||||||
|
- 王聪 Wang Cong <xiyou.wangcong@gmail.com>
|
||||||
|
|
||||||
|
|
||||||
如何让你的改动进入内核
|
提交补丁:如何让你的改动进入内核
|
||||||
======================
|
================================
|
||||||
|
|
||||||
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
|
对于想要将改动提交到 Linux 内核的个人或者公司来说,如果不熟悉“规矩”,
|
||||||
提交的流程会让人畏惧。本文档收集了一系列建议,这些建议可以大大的提高你
|
提交的流程会让人畏惧。本文档包含了一系列建议,可以大大提高你
|
||||||
的改动被接受的机会.
|
的改动被接受的机会.
|
||||||
|
|
||||||
以下文档含有大量简洁的建议, 具体请见:
|
本文档以较为简洁的行文给出了大量建议。关于内核开发流程如何进行的详细信息,
|
||||||
:ref:`Documentation/process <development_process_main>`
|
参见: Documentation/translations/zh_CN/process/development-process.rst 。
|
||||||
同样,:ref:`Documentation/translations/zh_CN/process/submit-checklist.rst <cn_submitchecklist>`
|
Documentation/translations/zh_CN/process/submit-checklist.rst 给出了一系列
|
||||||
给出在提交代码前需要检查的项目的列表。
|
提交补丁之前要检查的事项。设备树相关的补丁,请参阅
|
||||||
|
Documentation/devicetree/bindings/submitting-patches.rst 。
|
||||||
|
|
||||||
其中许多步骤描述了Git版本控制系统的默认行为;如果您使用Git来准备补丁,
|
本文档假设您正在使用 ``git`` 准备你的补丁。如果您不熟悉 ``git`` ,最好学习
|
||||||
您将发现它为您完成的大部分机械工作,尽管您仍然需要准备和记录一组合理的
|
如何使用它,这将使您作为内核开发人员的生活变得更加轻松。
|
||||||
补丁。一般来说,使用git将使您作为内核开发人员的生活更轻松。
|
|
||||||
|
|
||||||
|
部分子系统和维护人员的树有一些关于其工作流程和要求的额外信息,请参阅
|
||||||
|
Documentation/process/maintainer-handbooks.rst 。
|
||||||
|
|
||||||
0) 获取当前源码树
|
获取当前源码树
|
||||||
-----------------
|
--------------
|
||||||
|
|
||||||
如果您没有一个可以使用当前内核源代码的存储库,请使用git获取一个。您将要
|
如果您手头没有当前内核源代码的存储库,请使用 ``git`` 获取一份。您需要先获取
|
||||||
从主线存储库开始,它可以通过以下方式获取::
|
主线存储库,它可以通过以下命令拉取::
|
||||||
|
|
||||||
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
|
||||||
|
|
||||||
但是,请注意,您可能不希望直接针对主线树进行开发。大多数子系统维护人员运
|
但是,请注意,您可能不想直接针对主线树进行开发。大多数子系统维护人员运
|
||||||
行自己的树,并希望看到针对这些树准备的补丁。请参见MAINTAINERS文件中子系
|
行自己的树,并希望看到针对这些树准备的补丁。请参见MAINTAINERS文件中子系
|
||||||
统的 **T:** 项以查找该树,或者简单地询问维护者该树是否未在其中列出。
|
统的 **T:** 项以查找该树,或者直接询问维护者该树是否未在其中列出。
|
||||||
|
|
||||||
仍然可以通过tarballs下载内核版本(如下一节所述),但这是进行内核开发的
|
.. _zh_describe_changes:
|
||||||
一种困难的方式。
|
|
||||||
|
|
||||||
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`` <https://savannah.nongnu.org/projects/quilt> 另外一个流行的选择。
|
|
||||||
|
|
||||||
.. _cn_describe_changes:
|
|
||||||
|
|
||||||
2) 描述你的改动
|
|
||||||
---------------
|
|
||||||
|
|
||||||
描述你的问题。无论您的补丁是一行错误修复还是5000行新功能,都必须有一个潜在
|
描述你的问题。无论您的补丁是一行错误修复还是5000行新功能,都必须有一个潜在
|
||||||
的问题激励您完成这项工作。让审稿人相信有一个问题值得解决,让他们读完第一段
|
的问题激励您完成这项工作。说服审阅者相信有一个问题值得解决,让他们读完第一段
|
||||||
是有意义的。
|
后就能明白这一点。
|
||||||
|
|
||||||
描述用户可见的影响。直接崩溃和锁定是相当有说服力的,但并不是所有的错误都那么
|
描述用户可见的影响。直接崩溃和锁定是相当有说服力的,但并不是所有的错误都那么
|
||||||
明目张胆。即使在代码审查期间发现了这个问题,也要描述一下您认为它可能对用户产
|
明目张胆。即使在代码审阅期间发现了这个问题,也要描述一下您认为它可能对用户产
|
||||||
生的影响。请记住,大多数Linux安装运行的内核来自二级稳定树或特定于供应商/产品
|
生的影响。请记住,大多数Linux安装运行的内核来自二级稳定树或特定于供应商/产品
|
||||||
的树,只从上游精选特定的补丁,因此请包含任何可以帮助您将更改定位到下游的内容:
|
的树,只从上游精选特定的补丁,因此请包含任何可以帮助您将更改定位到下游的内容:
|
||||||
触发的场景、DMESG的摘录、崩溃描述、性能回归、延迟尖峰、锁定等。
|
触发的场景、DMESG的摘录、崩溃描述、性能回归、延迟尖峰、锁定等。
|
||||||
|
|
||||||
量化优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
|
质量优化和权衡。如果您声称在性能、内存消耗、堆栈占用空间或二进制大小方面有所
|
||||||
改进,请包括支持它们的数字。但也要描述不明显的成本。优化通常不是免费的,而是
|
改进,请包括支持它们的数据。但也要描述不明显的成本。优化通常不是零成本的,而是
|
||||||
在CPU、内存和可读性之间进行权衡;或者,探索性的工作,在不同的工作负载之间进
|
在CPU、内存和可读性之间进行权衡;或者,做探索性的工作,在不同的工作负载之间进
|
||||||
行权衡。请描述优化的预期缺点,以便审阅者可以权衡成本和收益。
|
行权衡。请描述优化的预期缺点,以便审阅者可以权衡成本和收益。
|
||||||
|
|
||||||
一旦问题建立起来,就要详细地描述一下您实际在做什么。对于审阅者来说,用简单的
|
提出问题之后,就要详细地描述一下您实际在做的技术细节。对于审阅者来说,用简练的
|
||||||
英语描述代码的变化是很重要的,以验证代码的行为是否符合您的意愿。
|
英语描述代码的变化是很重要的,以验证代码的行为是否符合您的意图。
|
||||||
|
|
||||||
如果您将补丁描述写在一个表单中,这个表单可以很容易地作为“提交日志”放入Linux
|
如果您将补丁描述写成“标准格式”,可以很容易地作为“提交日志”放入Linux的源代
|
||||||
的源代码管理系统git中,那么维护人员将非常感谢您。见 :ref:`cn_explicit_in_reply_to`.
|
码管理系统 ``git`` 中,那么维护人员将非常感谢您。
|
||||||
|
参见 :ref:`zh_the_canonical_patch_format` 。
|
||||||
|
|
||||||
每个补丁只解决一个问题。如果你的描述开始变长,这就表明你可能需要拆分你的补丁。
|
每个补丁只解决一个问题。如果你的描述开始变长,这就表明你可能需要拆分你的补丁。
|
||||||
请见 :ref:`cn_split_changes`
|
请见 :ref:`zh_split_changes` 。
|
||||||
|
|
||||||
提交或重新提交修补程序或修补程序系列时,请包括完整的修补程序说明和理由。不要
|
提交或重新提交补丁或补丁系列时,请包括完整的补丁说明和理由。不要
|
||||||
只说这是补丁(系列)的第几版。不要期望子系统维护人员引用更早的补丁版本或引用
|
只说这是补丁(系列)的第几版。不要期望子系统维护人员引用更早的补丁版本或引用
|
||||||
URL来查找补丁描述并将其放入补丁中。也就是说,补丁(系列)及其描述应该是独立的。
|
URL来查找补丁描述并将其放入补丁中。也就是说,补丁(系列)及其描述应该是独立的。
|
||||||
这对维护人员和审查人员都有好处。一些评审者可能甚至没有收到补丁的早期版本。
|
这对维护人员和审阅者都有好处。一些审阅者可能甚至没有收到补丁的早期版本。
|
||||||
|
|
||||||
描述你在命令语气中的变化,例如“make xyzzy do frotz”而不是“[This patch]make
|
用祈使句描述你的变更,例如“make xyzzy do frotz”而不是“[This patch]make
|
||||||
xyzzy do frotz”或“[I]changed xyzzy to do frotz”,就好像你在命令代码库改变
|
xyzzy do frotz”或“[I]changed xyzzy to do frotz”,就好像你在命令代码库改变
|
||||||
它的行为一样。
|
它的行为一样。
|
||||||
|
|
||||||
如果修补程序修复了一个记录的bug条目,请按编号和URL引用该bug条目。如果补丁来
|
如果您想要引用一个特定的提交,不要只引用提交的SHA-1 ID。还请包括提交的一行
|
||||||
自邮件列表讨论,请给出邮件列表存档的URL;使用带有 ``Message-ID`` 的
|
|
||||||
https://lore.kernel.org/ 重定向,以确保链接不会过时。
|
|
||||||
|
|
||||||
但是,在没有外部资源的情况下,尽量让你的解释可理解。除了提供邮件列表存档或
|
|
||||||
bug的URL之外,还要总结需要提交补丁的相关讨论要点。
|
|
||||||
|
|
||||||
如果您想要引用一个特定的提交,不要只引用提交的 SHA-1 ID。还请包括提交的一行
|
|
||||||
摘要,以便于审阅者了解它是关于什么的。例如::
|
摘要,以便于审阅者了解它是关于什么的。例如::
|
||||||
|
|
||||||
Commit e21d2170f36602ae2708 ("video: remove unnecessary
|
Commit e21d2170f36602ae2708 ("video: remove unnecessary
|
||||||
@ -144,82 +94,104 @@ bug的URL之外,还要总结需要提交补丁的相关讨论要点。
|
|||||||
platform_set_drvdata(), but left the variable "dev" unused,
|
platform_set_drvdata(), but left the variable "dev" unused,
|
||||||
delete it.
|
delete it.
|
||||||
|
|
||||||
您还应该确保至少使用前12位 SHA-1 ID. 内核存储库包含*许多*对象,使与较短的ID
|
您还应该确保至少使用前12位SHA-1 ID。内核存储库包含 *许多* 对象,使较短的ID
|
||||||
发生冲突的可能性很大。记住,即使现在不会与您的六个字符ID发生冲突,这种情况
|
发生冲突的可能性很大。记住,即使现在不会与您的六个字符ID发生冲突,这种情况
|
||||||
可能五年后改变。
|
也可能在五年后改变。
|
||||||
|
|
||||||
如果修补程序修复了特定提交中的错误,例如,使用 ``git bisct`` ,请使用带有前
|
如果该变更的相关讨论或背景信息可以在网上查阅,请加上“Link:”标签指向它。例如
|
||||||
12个字符SHA-1 ID 的"Fixes:"标记和单行摘要。为了简化不要将标记拆分为多个,
|
你的补丁修复了一个缺陷,需要添加一个带有URL的标签指向邮件列表存档或缺陷跟踪器
|
||||||
行、标记不受分析脚本“75列换行”规则的限制。例如::
|
的相关报告;如果该补丁是由一些早先邮件列表讨论或网络上的记录引起的,请指向它。
|
||||||
|
|
||||||
Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
|
当链接到邮件列表存档时,请首选lore.kernel.org邮件存档服务。用邮件中的
|
||||||
|
``Message-ID`` 头(去掉尖括号)可以创建链接URL。例如::
|
||||||
|
|
||||||
下列 ``git config`` 设置可以添加让 ``git log``, ``git show`` 漂亮的显示格式::
|
Link: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
|
||||||
|
|
||||||
|
请检查该链接以确保可用且指向正确的邮件。
|
||||||
|
|
||||||
|
不过,在没有外部资源的情况下,也要尽量让你的解释可理解。除了提供邮件列表存档或
|
||||||
|
缺陷的URL之外,还要需要总结该补丁的相关讨论要点。
|
||||||
|
|
||||||
|
如果补丁修复了特定提交中的错误,例如使用 ``git bisct`` 发现了一个问题,请使用
|
||||||
|
带有前12个字符SHA-1 ID的“Fixes:”标签和单行摘要。为了简化解析脚本,不要将该
|
||||||
|
标签拆分为多行,标签不受“75列换行”规则的限制。例如::
|
||||||
|
|
||||||
|
Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
|
||||||
|
|
||||||
|
下列 ``git config`` 设置可以让 ``git log``, ``git show`` 增加上述风格的显示格式::
|
||||||
|
|
||||||
[core]
|
[core]
|
||||||
abbrev = 12
|
abbrev = 12
|
||||||
[pretty]
|
[pretty]
|
||||||
fixes = Fixes: %h (\"%s\")
|
fixes = Fixes: %h (\"%s\")
|
||||||
|
|
||||||
.. _cn_split_changes:
|
使用示例::
|
||||||
|
|
||||||
3) 拆分你的改动
|
$ git log -1 --pretty=fixes 54a4f0239f2e
|
||||||
---------------
|
Fixes: 54a4f0239f2e ("KVM: MMU: make kvm_mmu_zap_page() return the number of pages it actually freed")
|
||||||
|
|
||||||
将每个逻辑更改分隔成一个单独的补丁。
|
.. _zh_split_changes:
|
||||||
|
|
||||||
|
拆分你的改动
|
||||||
|
------------
|
||||||
|
|
||||||
|
将每个 **逻辑更改** 拆分成一个单独的补丁。
|
||||||
|
|
||||||
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动拆分到两个或
|
例如,如果你的改动里同时有bug修正和性能优化,那么把这些改动拆分到两个或
|
||||||
者更多的补丁文件中。如果你的改动包含对API的修改,并且修改了驱动程序来适
|
者更多的补丁文件中。如果你的改动包含对API的修改,并且增加了一个使用该新API
|
||||||
应这些新的API,那么把这些修改分成两个补丁。
|
的驱动,那么把这些修改分成两个补丁。
|
||||||
|
|
||||||
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
|
另一方面,如果你将一个单独的改动做成多个补丁文件,那么将它们合并成一个
|
||||||
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
|
单独的补丁文件。这样一个逻辑上单独的改动只被包含在一个补丁文件里。
|
||||||
|
|
||||||
如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。简单的在你的补
|
需要记住的一点是,每个补丁的更改都应易于理解,以便审阅者验证。每个补丁都应该
|
||||||
丁描述里指出“这个补丁依赖某补丁”就好了。
|
对其价值进行阐述。
|
||||||
|
|
||||||
在将您的更改划分为一系列补丁时,要特别注意确保内核在系列中的每个补丁之后
|
如果有一个补丁依赖另外一个补丁来完成它的改动,那没问题。直接在你的补
|
||||||
都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何时
|
丁描述里指出 **“这个补丁依赖某补丁”** 就好了。
|
||||||
候分割你的补丁系列;如果你在中间引入错误,他们不会感谢你。
|
|
||||||
|
|
||||||
如果你不能将补丁浓缩成更少的文件,那么每次大约发送出15个,然后等待审查
|
在将您的更改划分为一系列补丁时,要特别注意确保内核在应用系列中的每个补丁之后
|
||||||
|
都能正常构建和运行。使用 ``git bisect`` 来追踪问题的开发者可能会在任何地方分
|
||||||
|
割你的补丁系列;如果你在中间引入错误,他们不会感谢你。
|
||||||
|
|
||||||
|
如果你不能将补丁系列浓缩得更小,那么每次大约发送出15个补丁,然后等待审阅
|
||||||
和集成。
|
和集成。
|
||||||
|
|
||||||
4) 检查你的更改风格
|
检查你的更改风格
|
||||||
-------------------
|
----------------
|
||||||
|
|
||||||
检查您的补丁是否存在基本样式冲突,详细信息可在
|
检查您的补丁是否违反了基本样式规定,详细信息参见
|
||||||
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
|
Documentation/translations/zh_CN/process/coding-style.rst
|
||||||
中找到。如果不这样做,只会浪费审稿人的时间,并且会导致你的补丁被拒绝,甚至
|
中找到。如果不这样做,只会浪费审阅者的时间,并且会导致你的补丁被拒绝,甚至
|
||||||
可能没有被阅读。
|
可能没有被阅读。
|
||||||
|
|
||||||
一个重要的例外是在将代码从一个文件移动到另一个文件时——在这种情况下,您不应
|
一个重要的例外是在将代码从一个文件移动到另一个文件时——在这种情况下,您不应
|
||||||
该在移动代码的同一个补丁中修改移动的代码。这清楚地描述了移动代码和您的更改
|
该在移动代码的同一个补丁中修改移动的代码。这清楚地描述了移动代码和您的更改
|
||||||
的行为。这大大有助于审查实际差异,并允许工具更好地跟踪代码本身的历史。
|
的行为。这大大有助于审阅实际差异,并允许工具更好地跟踪代码本身的历史。
|
||||||
|
|
||||||
在提交之前,使用补丁样式检查程序检查补丁(scripts/check patch.pl)。不过,
|
在提交之前,使用补丁样式检查程序检查补丁(scripts/check patch.pl)。不过,
|
||||||
请注意,样式检查程序应该被视为一个指南,而不是作为人类判断的替代品。如果您
|
请注意,样式检查程序应该被视为一个指南,而不是作为人类判断的替代品。如果您
|
||||||
的代码看起来更好,但有违规行为,那么最好不要使用它。
|
的代码看起来更好,但有违规行为,那么最好别管它。
|
||||||
|
|
||||||
检查者报告三个级别:
|
检查者报告三个级别:
|
||||||
|
|
||||||
- ERROR:很可能出错的事情
|
- ERROR:很可能出错的事情
|
||||||
- WARNING:需要仔细审查的事项
|
- WARNING:需要仔细审阅的事项
|
||||||
- CHECK:需要思考的事情
|
- CHECK:需要思考的事情
|
||||||
|
|
||||||
您应该能够判断您的补丁中存在的所有违规行为。
|
您应该能够判断您的补丁中存在的所有违规行为。
|
||||||
|
|
||||||
5) 选择补丁收件人
|
选择补丁收件人
|
||||||
-----------------
|
--------------
|
||||||
|
|
||||||
您应该总是在任何补丁上复制相应的子系统维护人员,以获得他们维护的代码;查看
|
您应该总是知会任何补丁相应代码的子系统维护人员;查看
|
||||||
维护人员文件和源代码修订历史记录,以了解这些维护人员是谁。脚本
|
维护人员文件和源代码修订历史记录,以了解这些维护人员是谁。脚本
|
||||||
scripts/get_Maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
|
scripts/get_maintainer.pl在这个步骤中非常有用。如果您找不到正在工作的子系统
|
||||||
的维护人员,那么Andrew Morton(akpm@linux-foundation.org)将充当最后的维护
|
的维护人员,那么Andrew Morton(akpm@linux-foundation.org)将充当最后的维护
|
||||||
人员。
|
人员。
|
||||||
|
|
||||||
您通常还应该选择至少一个邮件列表来接收补丁集的。linux-kernel@vger.kernel.org
|
您通常还应该选择至少一个邮件列表来接收补丁集的副本。linux-kernel@vger.kernel.org
|
||||||
作为最后一个解决办法的列表,但是这个列表上的体积已经引起了许多开发人员的拒绝。
|
是所有补丁的默认列表,但是这个列表的流量已经导致了许多开发人员不再看它。
|
||||||
在MAINTAINERS文件中查找子系统特定的列表;您的补丁可能会在那里得到更多的关注。
|
在MAINTAINERS文件中查找子系统特定的列表;您的补丁可能会在那里得到更多的关注。
|
||||||
不过,请不要发送垃圾邮件到无关的列表。
|
不过,请不要发送垃圾邮件到无关的列表。
|
||||||
|
|
||||||
@ -229,189 +201,170 @@ http://vger.kernel.org/vger-lists.html 上找到它们的列表。不过,也
|
|||||||
|
|
||||||
不要一次发送超过15个补丁到vger邮件列表!!!!
|
不要一次发送超过15个补丁到vger邮件列表!!!!
|
||||||
|
|
||||||
Linus Torvalds 是决定改动能否进入 Linux 内核的最终裁决者。他的 e-mail
|
Linus Torvalds是决定改动能否进入 Linux 内核的最终裁决者。他的邮件地址是
|
||||||
地址是 <torvalds@linux-foundation.org> 。他收到的 e-mail 很多,所以一般
|
torvalds@linux-foundation.org 。他收到的邮件很多,所以一般来说最好 **别**
|
||||||
的说,最好别给他发 e-mail。
|
给他发邮件。
|
||||||
|
|
||||||
如果您有修复可利用安全漏洞的补丁,请将该补丁发送到 security@kernel.org。对于
|
如果您有修复可利用安全漏洞的补丁,请将该补丁发送到 security@kernel.org 。对于
|
||||||
严重的bug,可以考虑短期暂停以允许分销商向用户发布补丁;在这种情况下,显然不应
|
严重的bug,可以考虑短期禁令以允许分销商(有时间)向用户发布补丁;在这种情况下,
|
||||||
将补丁发送到任何公共列表。
|
显然不应将补丁发送到任何公共列表。
|
||||||
|
参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。
|
||||||
|
|
||||||
修复已发布内核中严重错误的补丁程序应该指向稳定版维护人员,方法是放这样的一行::
|
修复已发布内核中严重错误的补丁程序应该抄送给稳定版维护人员,方法是把以下列行
|
||||||
|
放进补丁的签准区(注意,不是电子邮件收件人)::
|
||||||
|
|
||||||
Cc: stable@vger.kernel.org
|
Cc: stable@vger.kernel.org
|
||||||
|
|
||||||
进入补丁的签准区(注意,不是电子邮件收件人)。除了这个文件之外,您还应该阅读
|
除了本文件之外,您还应该阅读
|
||||||
:ref:`Documentation/process/stable-kernel-rules.rst <stable_kernel_rules>`
|
Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
|
||||||
|
|
||||||
但是,请注意,一些子系统维护人员希望得出他们自己的结论,即哪些补丁应该被放到
|
如果更改影响到用户侧内核接口,请向手册页维护人员(如维护人员文件中所列)发送
|
||||||
稳定的树上。尤其是网络维护人员,不希望看到单个开发人员在补丁中添加像上面这样
|
|
||||||
的行。
|
|
||||||
|
|
||||||
如果更改影响到用户和内核接口,请向手册页维护人员(如维护人员文件中所列)发送
|
|
||||||
手册页补丁,或至少发送更改通知,以便一些信息进入手册页。还应将用户空间API
|
手册页补丁,或至少发送更改通知,以便一些信息进入手册页。还应将用户空间API
|
||||||
更改复制到 linux-api@vger.kernel.org。
|
更改抄送到 linux-api@vger.kernel.org 。
|
||||||
|
|
||||||
|
|
||||||
6) 没有 MIME 编码,没有链接,没有压缩,没有附件,只有纯文本
|
不要MIME编码,不要链接,不要压缩,不要附件,只要纯文本
|
||||||
-----------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
|
||||||
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
|
Linus 和其他的内核开发者需要阅读和评论你提交的改动。对于内核开发者来说
|
||||||
,可以“引用”你的改动很重要,使用一般的 e-mail 工具,他们就可以在你的
|
,可以“引用”你的改动很重要,使用一般的邮件工具,他们就可以在你的
|
||||||
代码的任何位置添加评论。
|
代码的任何位置添加评论。
|
||||||
|
|
||||||
因为这个原因,所有的提交的补丁都是 e-mail 中“内嵌”的。
|
因为这个原因,所有的提交的补丁都是邮件中“内嵌”的。最简单(和推荐)的方法就
|
||||||
|
是使用 ``git send-email`` 。https://git-send-email.io 有 ``git send-email``
|
||||||
|
的交互式教程。
|
||||||
|
|
||||||
|
如果你选择不用 ``git send-email`` :
|
||||||
|
|
||||||
.. warning::
|
.. warning::
|
||||||
如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的补丁
|
|
||||||
|
|
||||||
不要将补丁作为 MIME 编码的附件,不管是否压缩。很多流行的 e-mail 软件不
|
如果你使用剪切-粘贴你的补丁,小心你的编辑器的自动换行功能破坏你的补丁
|
||||||
是任何时候都将 MIME 编码的附件当作纯文本发送的,这会使得别人无法在你的
|
|
||||||
代码中加评论。另外,MIME 编码的附件会让 Linus 多花一点时间来处理,这就
|
不要将补丁作为MIME编码的附件,不管是否压缩。很多流行的邮件软件不
|
||||||
|
是任何时候都将MIME编码的附件当作纯文本发送的,这会使得别人无法在你的
|
||||||
|
代码中加评论。另外,MIME编码的附件会让Linus多花一点时间来处理,这就
|
||||||
降低了你的改动被接受的可能性。
|
降低了你的改动被接受的可能性。
|
||||||
|
|
||||||
例外:如果你的邮递员弄坏了补丁,那么有人可能会要求你使用mime重新发送补丁
|
例外:如果你的邮路损坏了补丁,那么有人可能会要求你使用MIME重新发送补丁。
|
||||||
|
|
||||||
请参阅 :ref:`Documentation/translations/zh_CN/process/email-clients.rst <cn_email_clients>`
|
请参阅 Documentation/translations/zh_CN/process/email-clients.rst
|
||||||
以获取有关配置电子邮件客户端以使其不受影响地发送修补程序的提示。
|
以获取有关配置电子邮件客户端以使其不受影响地发送补丁的提示。
|
||||||
|
|
||||||
7) e-mail 的大小
|
回复审阅意见
|
||||||
|
------------
|
||||||
|
|
||||||
|
你的补丁几乎肯定会得到审阅者对补丁改进方法的评论(以回复邮件的形式)。您必须
|
||||||
|
对这些评论作出回应;让补丁被忽略的一个好办法就是忽略审阅者的意见。直接回复邮
|
||||||
|
件来回应意见即可。不会导致代码更改的意见或问题几乎肯定会带来注释或变更日志的
|
||||||
|
改变,以便下一个审阅者更好地了解正在发生的事情。
|
||||||
|
|
||||||
|
一定要告诉审阅者你在做什么改变,并感谢他们的时间。代码审阅是一个累人且耗时的
|
||||||
|
过程,审阅者有时会变得暴躁。即使在这种情况下,也要礼貌地回应并解决他们指出的
|
||||||
|
问题。当发送下一版时,在封面邮件或独立补丁里加上 ``patch changelog`` 说明与
|
||||||
|
前一版本的不同之处(参见 :ref:`zh_the_canonical_patch_format` )。
|
||||||
|
|
||||||
|
.. _zh_resend_reminders:
|
||||||
|
|
||||||
|
不要泄气或不耐烦
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
大的改动对邮件列表不合适,对某些维护者也不合适。如果你的补丁,在不压缩
|
提交更改后,请耐心等待。审阅者是大忙人,可能无法立即审阅您的补丁。
|
||||||
的情况下,超过了300kB,那么你最好将补丁放在一个能通过 internet 访问的服
|
|
||||||
务器上,然后用指向你的补丁的 URL 替代。但是请注意,如果您的补丁超过了
|
|
||||||
300kb,那么它几乎肯定需要被破坏。
|
|
||||||
|
|
||||||
8)回复评审意见
|
曾几何时,补丁曾在没收到评论的情况下消失在虚空中,但现在开发过程应该更加顺利了。
|
||||||
---------------
|
|
||||||
|
|
||||||
你的补丁几乎肯定会得到评审者对补丁改进方法的评论。您必须对这些评论作出
|
|
||||||
回应;让补丁被忽略的一个好办法就是忽略审阅者的意见。不会导致代码更改的
|
|
||||||
意见或问题几乎肯定会带来注释或变更日志的改变,以便下一个评审者更好地了解
|
|
||||||
正在发生的事情。
|
|
||||||
|
|
||||||
一定要告诉审稿人你在做什么改变,并感谢他们的时间。代码审查是一个累人且
|
|
||||||
耗时的过程,审查人员有时会变得暴躁。即使在这种情况下,也要礼貌地回应并
|
|
||||||
解决他们指出的问题。
|
|
||||||
|
|
||||||
9)不要泄气或不耐烦
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
提交更改后,请耐心等待。审阅者是忙碌的人,可能无法立即访问您的修补程序。
|
|
||||||
|
|
||||||
曾几何时,补丁曾在没有评论的情况下消失在空白中,但开发过程比现在更加顺利。
|
|
||||||
您应该在一周左右的时间内收到评论;如果没有收到评论,请确保您已将补丁发送
|
您应该在一周左右的时间内收到评论;如果没有收到评论,请确保您已将补丁发送
|
||||||
到正确的位置。在重新提交或联系审阅者之前至少等待一周-在诸如合并窗口之类的
|
到正确的位置。在重新提交或联系审阅者之前至少等待一周——在诸如合并窗口之类的
|
||||||
繁忙时间可能更长。
|
繁忙时间可能更长。
|
||||||
|
|
||||||
10)主题中包含 PATCH
|
在等了几个星期后,用带RESEND的主题重发补丁也是可以的::
|
||||||
--------------------
|
|
||||||
|
|
||||||
由于到linus和linux内核的电子邮件流量很高,通常会在主题行前面加上[PATCH]
|
[PATCH Vx RESEND] sub/sys: Condensed patch summary
|
||||||
前缀. 这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。
|
|
||||||
|
|
||||||
11)签署你的作品-开发者原始认证
|
当你发布补丁(系列)修改版的时候,不要加上“RESEND”——“RESEND”只适用于重
|
||||||
-------------------------------
|
新提交之前未经修改的补丁(系列)。
|
||||||
|
|
||||||
为了加强对谁做了何事的追踪,尤其是对那些透过好几层的维护者的补丁,我们
|
主题中包含 PATCH
|
||||||
建议在发送出去的补丁上加一个 “sign-off” 的过程。
|
----------------
|
||||||
|
|
||||||
"sign-off" 是在补丁的注释的最后的简单的一行文字,认证你编写了它或者其他
|
由于到Linus和linux-kernel的电子邮件流量很高,通常会在主题行前面加上[PATCH]
|
||||||
|
前缀。这使Linus和其他内核开发人员更容易将补丁与其他电子邮件讨论区分开。
|
||||||
|
|
||||||
|
``git send-email`` 会自动为你加上。
|
||||||
|
|
||||||
|
签署你的作品——开发者来源认证
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
为了加强对谁做了何事的追踪,尤其是对那些透过好几层维护者才最终到达的补丁,我
|
||||||
|
们在通过邮件发送的补丁上引入了“签署(sign-off)”流程。
|
||||||
|
|
||||||
|
“签署”是在补丁注释最后的一行简单文字,认证你编写了它或者其他
|
||||||
人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息:
|
人有权力将它作为开放源代码的补丁传递。规则很简单:如果你能认证如下信息:
|
||||||
|
|
||||||
开发者来源证书 1.1
|
开发者来源认证 1.1
|
||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
对于本项目的贡献,我认证如下信息:
|
对于本项目的贡献,我认证如下信息:
|
||||||
|
|
||||||
(a)这些贡献是完全或者部分的由我创建,我有权利以文件中指出
|
(a) 这些贡献是完全或者部分的由我创建,我有权利以文件中指出
|
||||||
的开放源代码许可证提交它;或者
|
的开放源代码许可证提交它;或者
|
||||||
(b)这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
|
|
||||||
源代码许可证保护,而且,根据许可证,我有权提交修改后的贡献,
|
(b) 这些贡献基于以前的工作,据我所知,这些以前的工作受恰当的开放
|
||||||
|
源代码许可证保护,而且,根据文件中指出的许可证,我有权提交修改后的贡献,
|
||||||
无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
|
无论是完全还是部分由我创造,这些贡献都使用同一个开放源代码许可证
|
||||||
(除非我被允许用其它的许可证),正如文件中指出的;或者
|
(除非我被允许用其它的许可证);或者
|
||||||
(c)这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
|
|
||||||
|
(c) 这些贡献由认证(a),(b)或者(c)的人直接提供给我,而
|
||||||
且我没有修改它。
|
且我没有修改它。
|
||||||
(d)我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
|
|
||||||
一起提交的个人记录,包括 sign-off )被永久维护并且可以和这个项目
|
(d) 我理解并同意这个项目和贡献是公开的,贡献的记录(包括我
|
||||||
|
一起提交的个人记录,包括sign-off)被永久维护并且可以和这个项目
|
||||||
或者开放源代码的许可证同步地再发行。
|
或者开放源代码的许可证同步地再发行。
|
||||||
|
|
||||||
那么加入这样一行::
|
那么加入这样一行::
|
||||||
|
|
||||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
Signed-off-by: Random J Developer <random@developer.example.org>
|
||||||
|
|
||||||
使用你的真名(抱歉,不能使用假名或者匿名。)
|
使用你的真名(抱歉,不能使用假名或者匿名。)如果使用 ``git commit -s`` 的话
|
||||||
|
将会自动完成。撤销也应当包含“Signed-off-by”, ``git revert -s`` 会帮你搞定。
|
||||||
|
|
||||||
有人在最后加上标签。现在这些东西会被忽略,但是你可以这样做,来标记公司
|
有些人会在最后加上额外的标签。现在这些东西会被忽略,但是你可以这样做,来标记
|
||||||
内部的过程,或者只是指出关于 sign-off 的一些特殊细节。
|
公司内部的过程,或者只是指出关于签署的一些特殊细节。
|
||||||
|
|
||||||
如果您是子系统或分支维护人员,有时需要稍微修改收到的补丁,以便合并它们,
|
作者签署之后的任何其他签署(Signed-off-by:'s)均来自处理和传递补丁的人员,但
|
||||||
因为树和提交者中的代码不完全相同。如果你严格遵守规则(c),你应该要求提交者
|
未参与其开发。签署链应当反映补丁传播到维护者并最终传播到Linus所经过的 **真实**
|
||||||
重新发布,但这完全是在浪费时间和精力。规则(b)允许您调整代码,但是更改一个
|
路径,首个签署指明单个作者的主要作者身份。
|
||||||
提交者的代码并让他认可您的错误是非常不礼貌的。要解决此问题,建议在最后一个
|
|
||||||
由签名行和您的行之间添加一行,指示更改的性质。虽然这并不是强制性的,但似乎
|
|
||||||
在描述前加上您的邮件和/或姓名(全部用方括号括起来),这足以让人注意到您对最
|
|
||||||
后一分钟的更改负有责任。例如::
|
|
||||||
|
|
||||||
Signed-off-by: Random J Developer <random@developer.example.org>
|
何时使用Acked-by:,CC:,和Co-Developed by:
|
||||||
[lucky@maintainer.example.org: struct foo moved from foo.c to foo.h]
|
------------------------------------------
|
||||||
Signed-off-by: Lucky K Maintainer <lucky@maintainer.example.org>
|
|
||||||
|
|
||||||
如果您维护一个稳定的分支机构,同时希望对作者进行致谢、跟踪更改、合并修复并
|
Singed-off-by: 标签表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。
|
||||||
保护提交者不受投诉,那么这种做法尤其有用。请注意,在任何情况下都不能更改作者
|
|
||||||
的ID(From 头),因为它是出现在更改日志中的标识。
|
|
||||||
|
|
||||||
对回合(back-porters)的特别说明:在提交消息的顶部(主题行之后)插入一个补丁
|
如果一个人没有直接参与补丁的准备或处理,但希望表示并记录他们对补丁的批准/赞成,
|
||||||
的起源指示似乎是一种常见且有用的实践,以便于跟踪。例如,下面是我们在3.x稳定
|
那么他们可以要求在补丁的变更日志中添加一个Acked-by:。
|
||||||
版本中看到的内容::
|
|
||||||
|
|
||||||
Date: Tue Oct 7 07:26:38 2014 -0400
|
Acked-by: 通常由受影响代码的维护者使用,当该维护者既没有贡献也没有转发补丁时。
|
||||||
|
|
||||||
libata: Un-break ATA blacklist
|
Acked-by: 不像签署那样正式。这是一个记录,确认人至少审阅了补丁,并表示接受。
|
||||||
|
因此,补丁合并有时会手动将Acker的“Yep,looks good to me”转换为 Acked-By:(但
|
||||||
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)。
|
请注意,通常最好要求一个明确的Ack)。
|
||||||
|
|
||||||
Acked-by:不一定表示对整个补丁的确认。例如,如果一个补丁影响多个子系统,并且
|
Acked-by:不一定表示对整个补丁的确认。例如,如果一个补丁影响多个子系统,并且
|
||||||
有一个:来自一个子系统维护者,那么这通常表示只确认影响维护者代码的部分。这里
|
有一个来自某个子系统维护者的Acked-By:,那么这通常表示只确认影响维护者代码的部
|
||||||
应该仔细判断。如有疑问,应参考邮件列表档案中的原始讨论。
|
分。这里应该仔细判断。如有疑问,应参考邮件列表存档中的原始讨论。
|
||||||
|
|
||||||
如果某人有机会对补丁进行评论,但没有提供此类评论,您可以选择在补丁中添加 ``Cc:``
|
如果某人本应有机会对补丁进行评论,但没有提供此类评论,您可以选择在补丁中添加
|
||||||
这是唯一一个标签,它可以在没有被它命名的人显式操作的情况下添加,但它应该表明
|
``Cc:`` 这是唯一可以在没有被该人明确同意的情况下添加的标签——但它应该表明
|
||||||
这个人是在补丁上抄送的。讨论中包含了潜在利益相关方。
|
这个人是在补丁上抄送的。此标签记录了讨论中包含的潜在利益相关方。
|
||||||
|
|
||||||
Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上工
|
Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上工
|
||||||
作时,它用于将属性赋予共同作者(除了 From: 所赋予的作者之外)。因为
|
作时,它用于给出共同作者(除了From:所给出的作者之外)。因为Co-developed-by:
|
||||||
Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟在相关合作作者的
|
表示作者身份,所以每个Co-developed-by:必须紧跟在相关合作作者的签署之后。标准
|
||||||
签名之后。标准的签核程序要求:标记的签核顺序应尽可能反映补丁的时间历史,而不
|
签署程序要求Singed-off-by:标签的顺序应尽可能反映补丁的时间历史,无论作者是通
|
||||||
管作者是通过 From :还是由 Co-developed-by: 共同开发的。值得注意的是,最后一
|
过From:还是Co-developed-by:表明。值得注意的是,最后一个Singed-off-by:必须是
|
||||||
个签字人:必须始终是提交补丁的开发人员。
|
提交补丁的开发人员。
|
||||||
|
|
||||||
注意,当作者也是电子邮件标题“发件人:”行中列出的人时,“From: ” 标记是可选的。
|
注意,如果From:作者也是电子邮件标题的From:行中列出的人,则From:标签是可选的。
|
||||||
|
|
||||||
作者提交的补丁程序示例::
|
被From:作者提交的补丁示例::
|
||||||
|
|
||||||
<changelog>
|
<changelog>
|
||||||
|
|
||||||
@ -421,7 +374,7 @@ Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟
|
|||||||
Signed-off-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>
|
Signed-off-by: From Author <from@author.example.org>
|
||||||
|
|
||||||
合作开发者提交的补丁示例::
|
被合作开发者提交的补丁示例::
|
||||||
|
|
||||||
From: From Author <from@author.example.org>
|
From: From Author <from@author.example.org>
|
||||||
|
|
||||||
@ -434,76 +387,85 @@ Co-developed-by: 表示作者身份,所以每个共同开发人:必须紧跟
|
|||||||
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
|
Signed-off-by: Submitting Co-Author <sub@coauthor.example.org>
|
||||||
|
|
||||||
|
|
||||||
13)使用报告人:、测试人:、审核人:、建议人:、修复人:
|
使用Reported-by:、Tested-by:、Reviewed-by:、Suggested-by:和Fixes:
|
||||||
--------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
Reported-by: 给那些发现错误并报告错误的人致谢,它希望激励他们在将来再次帮助
|
Reported-by: 给那些发现错误并报告错误的人致谢,它希望激励他们在将来再次帮助
|
||||||
我们。请注意,如果bug是以私有方式报告的,那么在使用Reported-by标记之前,请
|
我们。请注意,如果bug是以私有方式报告的,那么在使用Reported-by标签之前,请
|
||||||
先请求权限。
|
先请求许可。此标签是为Bug设计的;请不要将其用于感谢功能请求。
|
||||||
|
|
||||||
Tested-by: 标记表示补丁已由指定的人(在某些环境中)成功测试。这个标签通知
|
Tested-by: 标签表示补丁已由指定的人(在某些环境中)成功测试。这个标签通知
|
||||||
维护人员已经执行了一些测试,为将来的补丁提供了一种定位测试人员的方法,并确
|
维护人员已经执行了一些测试,为将来的补丁提供了一种定位测试人员的方法,并彰显测试人员的功劳。
|
||||||
保测试人员的信誉。
|
|
||||||
|
|
||||||
Reviewed-by:相反,根据审查人的声明,表明该补丁已被审查并被认为是可接受的:
|
Reviewed-by:根据审阅者的监督声明,表明该补丁已被审阅并被认为是可接受的:
|
||||||
|
|
||||||
|
|
||||||
审查人的监督声明
|
审阅者的监督声明
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
通过提供我的 Reviewed-by,我声明:
|
通过提供我的Reviewed-by:标签,我声明:
|
||||||
|
|
||||||
(a) 我已经对这个补丁进行了一次技术审查,以评估它是否适合被包含到
|
(a) 我已经对这个补丁进行了一次技术审阅,以评估它是否适合被包含到
|
||||||
主线内核中。
|
主线内核中。
|
||||||
|
|
||||||
(b) 与补丁相关的任何问题、顾虑或问题都已反馈给提交者。我对提交者对
|
(b) 与补丁相关的任何问题、顾虑或问题都已反馈给提交者。我对提交者对
|
||||||
我的评论的回应感到满意。
|
我的评论的回应感到满意。
|
||||||
|
|
||||||
(c) 虽然这一提交可能会改进一些东西,但我相信,此时,(1)对内核
|
(c) 虽然这一提交可能仍可被改进,但我相信,此时,(1)对内核
|
||||||
进行了有价值的修改,(2)没有包含争论中涉及的已知问题。
|
进行了有价值的修改,(2)没有包含争论中涉及的已知问题。
|
||||||
|
|
||||||
(d) 虽然我已经审查了补丁并认为它是健全的,但我不会(除非另有明确
|
(d) 虽然我已经审阅了补丁并认为它是健全的,但我不会(除非另有明确
|
||||||
说明)作出任何保证或保证它将在任何给定情况下实现其规定的目的
|
说明)作出任何保证或担保它会在任何给定情况下实现其规定的目的
|
||||||
或正常运行。
|
或正常运行。
|
||||||
|
|
||||||
Reviewed-by 是一种观点声明,即补丁是对内核的适当修改,没有任何遗留的严重技术
|
Reviewed-by是一种观点声明,即补丁是对内核的适当修改,没有任何遗留的严重技术
|
||||||
问题。任何感兴趣的审阅者(完成工作的人)都可以为一个补丁提供一个 Review-by
|
问题。任何感兴趣的审阅者(完成工作的人)都可以为一个补丁提供一个Reviewed-by
|
||||||
标签。此标签用于向审阅者提供致谢,并通知维护者已在修补程序上完成的审阅程度。
|
标签。此标签用于向审阅者提供致谢,并通知维护者补丁的审阅进度。
|
||||||
Reviewed-by: 当由已知了解主题区域并执行彻底检查的审阅者提供时,通常会增加
|
当Reviewed-by:标签由已知了解主题区域并执行彻底检查的审阅者提供时,通常会增加
|
||||||
补丁进入内核的可能性。
|
补丁进入内核的可能性。
|
||||||
|
|
||||||
|
一旦从测试人员或审阅者的“Tested-by”和“Reviewed-by”标签出现在邮件列表中,
|
||||||
|
作者应在发送下一个版本时将其添加到适用的补丁中。但是,如果补丁在以下版本中发
|
||||||
|
生了实质性更改,这些标签可能不再适用,因此应该删除。通常,在补丁更改日志中
|
||||||
|
(在 ``---`` 分隔符之后)应该提到删除某人的测试者或审阅者标签。
|
||||||
|
|
||||||
Suggested-by: 表示补丁的想法是由指定的人提出的,并确保将此想法归功于指定的
|
Suggested-by: 表示补丁的想法是由指定的人提出的,并确保将此想法归功于指定的
|
||||||
人。请注意,未经许可,不得添加此标签,特别是如果该想法未在公共论坛上发布。
|
人。请注意,未经许可,不得添加此标签,特别是如果该想法未在公共论坛上发布。
|
||||||
这就是说,如果我们勤快地致谢我们的创意者,他们很有希望在未来得到鼓舞,再次
|
也就是说,如果我们勤快地致谢创意提供者,他们将受到鼓舞,很有希望在未来再次
|
||||||
帮助我们。
|
帮助我们。
|
||||||
|
|
||||||
Fixes: 指示补丁在以前的提交中修复了一个问题。它可以很容易地确定错误的来源,
|
Fixes: 指示补丁修复了之前提交的一个问题。它可以便于确定错误的来源,这有助于
|
||||||
这有助于检查错误修复。这个标记还帮助稳定内核团队确定应该接收修复的稳定内核
|
检查错误修复。这个标签还帮助稳定内核团队确定应该接收修复的稳定内核版本。这是
|
||||||
版本。这是指示补丁修复的错误的首选方法。请参阅 :ref:`cn_describe_changes`
|
指示补丁修复的错误的首选方法。请参阅 :ref:`zh_describe_changes` 了解更多信息。
|
||||||
描述您的更改以了解更多详细信息。
|
|
||||||
|
|
||||||
.. _cn_the_canonical_patch_format:
|
.. note::
|
||||||
|
|
||||||
12)标准补丁格式
|
附加Fixes:标签不会改变稳定内核规则流程,也不改变所有稳定版补丁抄送
|
||||||
----------------
|
stable@vger.kernel.org的要求。有关更多信息,请阅读
|
||||||
|
Documentation/translations/zh_CN/process/stable-kernel-rules.rst 。
|
||||||
|
|
||||||
|
.. _zh_the_canonical_patch_format:
|
||||||
|
|
||||||
|
标准补丁格式
|
||||||
|
------------
|
||||||
|
|
||||||
本节描述如何格式化补丁本身。请注意,如果您的补丁存储在 ``Git`` 存储库中,则
|
本节描述如何格式化补丁本身。请注意,如果您的补丁存储在 ``Git`` 存储库中,则
|
||||||
可以使用 ``git format-patch`` 进行正确的补丁格式设置。但是,这些工具无法创建
|
可以使用 ``git format-patch`` 进行正确的补丁格式化。但是,这些工具无法创建
|
||||||
必要的文本,因此请务必阅读下面的说明。
|
必要的文本,因此请务必阅读下面的说明。
|
||||||
|
|
||||||
标准的补丁,标题行是::
|
标准的补丁标题行是::
|
||||||
|
|
||||||
Subject: [PATCH 001/123] 子系统:一句话概述
|
Subject: [PATCH 001/123] 子系统:一句话概述
|
||||||
|
|
||||||
标准补丁的信体存在如下部分:
|
标准补丁的信体包含如下部分:
|
||||||
|
|
||||||
- 一个 "from" 行指出补丁作者。后跟空行(仅当发送修补程序的人不是作者时才需要)。
|
- 一个 ``from`` 行指出补丁作者。后跟空行(仅当发送补丁的人不是作者时才需要)。
|
||||||
|
|
||||||
- 解释的正文,行以75列包装,这将被复制到永久变更日志来描述这个补丁。
|
- 说明文字,每行最长75列,这将被复制到永久变更日志来描述这个补丁。
|
||||||
|
|
||||||
- 一个空行
|
- 一个空行
|
||||||
|
|
||||||
- 上面描述的“Signed-off-by” 行,也将出现在更改日志中。
|
- 上述的 ``Signed-off-by:`` 行,也将出现在更改日志中。
|
||||||
|
|
||||||
- 只包含 ``---`` 的标记线。
|
- 只包含 ``---`` 的标记线。
|
||||||
|
|
||||||
@ -511,29 +473,29 @@ Fixes: 指示补丁在以前的提交中修复了一个问题。它可以很容
|
|||||||
|
|
||||||
- 实际补丁( ``diff`` 输出)。
|
- 实际补丁( ``diff`` 输出)。
|
||||||
|
|
||||||
标题行的格式,使得对标题行按字母序排序非常的容易 - 很多 e-mail 客户端都
|
标题行的格式,使得对标题行按字母序排序非常的容易——很多邮件客户端都
|
||||||
可以支持 - 因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
|
可以支持——因为序列号是用零填充的,所以按数字排序和按字母排序是一样的。
|
||||||
|
|
||||||
e-mail 标题中的“子系统”标识哪个内核子系统将被打补丁。
|
邮件标题中的“子系统”标识哪个内核子系统将被打补丁。
|
||||||
|
|
||||||
e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。“一句话概述”
|
邮件标题中的“一句话概述”扼要的描述邮件中的补丁。“一句话概述”
|
||||||
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
|
不应该是一个文件名。对于一个补丁系列(“补丁系列”指一系列的多个相关补
|
||||||
丁),不要对每个补丁都使用同样的“一句话概述”。
|
丁),不要对每个补丁都使用同样的“一句话概述”。
|
||||||
|
|
||||||
记住 e-mail 的“一句话概述”会成为该补丁的全局唯一标识。它会蔓延到 git
|
记住邮件的“一句话概述”会成为该补丁的全局唯一标识。它会进入 ``git``
|
||||||
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
|
的改动记录里。然后“一句话概述”会被用在开发者的讨论里,用来指代这个补
|
||||||
丁。用户将希望通过 google 来搜索"一句话概述"来找到那些讨论这个补丁的文
|
丁。用户将希望通过搜索引擎搜索“一句话概述”来找到那些讨论这个补丁的文
|
||||||
章。当人们在两三个月后使用诸如 ``gitk`` 或 ``git log --oneline`` 之类
|
章。当人们在两三个月后使用诸如 ``gitk`` 或 ``git log --oneline`` 之类
|
||||||
的工具查看数千个补丁时,也会很快看到它。
|
的工具查看数千个补丁时,也会很快看到它。
|
||||||
|
|
||||||
出于这些原因,概述必须不超过70-75个字符,并且必须描述补丁的更改以及为
|
出于这些原因,概述必须不超过70-75个字符,并且必须描述补丁的更改以及为
|
||||||
什么需要补丁。既要简洁又要描述性很有挑战性,但写得好的概述应该这样做。
|
什么需要补丁。既要简洁又要描述性很有挑战性,但写得好的概述应该这样。
|
||||||
|
|
||||||
概述的前缀可以用方括号括起来:“Subject: [PATCH <tag>...] <概述>”。标记
|
概述的前缀可以用方括号括起来:“Subject: [PATCH <tag>...] <概述>”。标记
|
||||||
不被视为概述的一部分,而是描述应该如何处理补丁。如果补丁的多个版本已发
|
不被视为概述的一部分,而是描述应该如何处理补丁。如果补丁的多个版本已发
|
||||||
送出来以响应评审(即“v1,v2,v3”)或“rfc”,以指示评审请求,那么通用标记
|
送出来以响应评审(即“v1,v2,v3”)则必须包含版本号,或包含“RFC”以指示
|
||||||
可能包括版本描述符。如果一个补丁系列中有四个补丁,那么各个补丁可以这样
|
评审请求。如果一个补丁系列中有四个补丁,那么各个补丁可以这样编号:1/4、2/4、
|
||||||
编号:1/4、2/4、3/4、4/4。这可以确保开发人员了解补丁应用的顺序,并且他们
|
3/4、4/4。这可以确保开发人员了解补丁应用的顺序,且
|
||||||
已经查看或应用了补丁系列中的所有补丁。
|
已经查看或应用了补丁系列中的所有补丁。
|
||||||
|
|
||||||
一些标题的例子::
|
一些标题的例子::
|
||||||
@ -541,95 +503,134 @@ e-mail 标题中的“一句话概述”扼要的描述 e-mail 中的补丁。
|
|||||||
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
|
Subject: [patch 2/5] ext2: improve scalability of bitmap searching
|
||||||
Subject: [PATCHv2 001/207] x86: fix eflags tracking
|
Subject: [PATCHv2 001/207] x86: fix eflags tracking
|
||||||
|
|
||||||
"From" 行是信体里的最上面一行,具有如下格式:
|
``From`` 行是信体里的最上面一行,具有如下格式::
|
||||||
|
|
||||||
From: Patch Author <author@example.com>
|
From: Patch Author <author@example.com>
|
||||||
|
|
||||||
"From" 行指明在永久改动日志里,谁会被确认为作者。如果没有 "From" 行,那
|
``From`` 行指明在永久改动日志里,谁会被确认为作者。如果没有 ``From`` 行,那
|
||||||
么邮件头里的 "From: " 行会被用来决定改动日志中的作者。
|
么邮件头里的 ``From:`` 行会被用来决定改动日志中的作者。
|
||||||
|
|
||||||
说明的主题将会被提交到永久的源代码改动日志里,因此对那些早已经不记得和
|
说明文字将会被提交到永久的源代码改动日志里,因此应针对那些早已经不记得和这
|
||||||
这个补丁相关的讨论细节的有能力的读者来说,是有意义的。包括补丁程序定位
|
个补丁相关的讨论细节的读者。包括补丁处理的故障症状(内核日志消息、oops消息
|
||||||
错误的(内核日志消息、OOPS消息等)症状,对于搜索提交日志以寻找适用补丁的人
|
等),这对于可能正在搜索提交日志以查找适用补丁的人特别有用。文本应该写得如
|
||||||
尤其有用。如果一个补丁修复了一个编译失败,那么可能不需要包含所有编译失败;
|
此详细,以便在数周、数月甚至数年后阅读时,能够为读者提供所需的细节信息,以
|
||||||
|
掌握创建补丁的 **原因** 。
|
||||||
|
|
||||||
|
如果一个补丁修复了一个编译失败,那么可能不需要包含 *所有* 编译失败;
|
||||||
只要足够让搜索补丁的人能够找到它就行了。与概述一样,既要简洁又要描述性。
|
只要足够让搜索补丁的人能够找到它就行了。与概述一样,既要简洁又要描述性。
|
||||||
|
|
||||||
"---" 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
|
``---`` 标记行对于补丁处理工具要找到哪里是改动日志信息的结束,是不可缺少
|
||||||
的。
|
的。
|
||||||
|
|
||||||
对于 "---" 标记之后的额外注解,一个好的用途就是用来写 diffstat,用来显
|
对于 ``---`` 标记之后的额外注解,一个好的用途就是用来写 ``diffstat`` ,用来显
|
||||||
示修改了什么文件和每个文件都增加和删除了多少行。diffstat 对于比较大的补
|
示修改了什么文件和每个文件都增加和删除了多少行。 ``diffstat`` 对于比较大的补
|
||||||
丁特别有用。其余那些只是和时刻或者开发者相关的注解,不合适放到永久的改
|
丁特别有用。
|
||||||
动日志里的,也应该放这里。
|
使用 ``diffstat`` 的选项 ``-p 1 -w 70`` 这样文件名就会从内核源代码树的目录开始
|
||||||
使用 diffstat的选项 "-p 1 -w 70" 这样文件名就会从内核源代码树的目录开始
|
|
||||||
,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
|
,不会占用太宽的空间(很容易适合80列的宽度,也许会有一些缩进。)
|
||||||
|
( ``git`` 默认会生成合适的diffstat。)
|
||||||
|
|
||||||
在后面的参考资料中能看到适当的补丁格式的更多细节。
|
其余那些只适用于当时或者与维护者相关的注解,不合适放到永久的改动日志里的,也
|
||||||
|
应该放这里。较好的例子就是 ``补丁更改记录`` ,记录了v1和v2版本补丁之间的差异。
|
||||||
|
|
||||||
.. _cn_explicit_in_reply_to:
|
请将此信息放在将变更日志与补丁的其余部分分隔开的 ``---`` 行 **之后** 。版本
|
||||||
|
信息不是提交到git树的变更日志的一部分。只是供审阅人员使用的附加信息。如果将
|
||||||
|
其放置在提交标记上方,则需要手动交互才能将其删除。如果它位于分隔线以下,则在
|
||||||
|
应用补丁时会自动剥离::
|
||||||
|
|
||||||
15) 明确回复邮件头(In-Reply-To)
|
<commit message>
|
||||||
-------------------------------
|
...
|
||||||
|
Signed-off-by: Author <author@mail>
|
||||||
|
---
|
||||||
|
V2 -> V3: Removed redundant helper function
|
||||||
|
V1 -> V2: Cleaned up coding style and addressed review comments
|
||||||
|
|
||||||
手动添加回复补丁的的标题头(In-Reply_To:) 是有帮助的(例如,使用 ``git send-email`` )
|
path/to/file | 5+++--
|
||||||
将补丁与以前的相关讨论关联起来,例如,将bug修复程序链接到电子邮件和bug报告。
|
...
|
||||||
|
|
||||||
|
在后面的参考资料中能看到正确补丁格式的更多细节。
|
||||||
|
|
||||||
|
.. _zh_backtraces:
|
||||||
|
|
||||||
|
提交消息中的回溯(Backtraces)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
回溯有助于记录导致问题的调用链。然而,并非所有回溯都有帮助。例如,早期引导调
|
||||||
|
用链是独特而明显的。而逐字复制完整的dmesg输出则会增加时间戳、模块列表、寄存
|
||||||
|
器和堆栈转储等分散注意力的信息。
|
||||||
|
|
||||||
|
因此,最有用的回溯应该从转储中提取相关信息,以更容易集中在真实问题上。下面是
|
||||||
|
一个剪裁良好的回溯示例::
|
||||||
|
|
||||||
|
unchecked MSR access error: WRMSR to 0xd51 (tried to write 0x0000000000000064)
|
||||||
|
at rIP: 0xffffffffae059994 (native_write_msr+0x4/0x20)
|
||||||
|
Call Trace:
|
||||||
|
mba_wrmsr
|
||||||
|
update_domains
|
||||||
|
rdtgroup_mkdir
|
||||||
|
|
||||||
|
.. _zh_explicit_in_reply_to:
|
||||||
|
|
||||||
|
明确回复邮件头(In-Reply-To)
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
手动添加回复补丁的的邮件头(In-Reply_To:)是有用的(例如,使用 ``git send-email`` ),
|
||||||
|
可以将补丁与以前的相关讨论关联起来,例如,将bug补丁链接到电子邮件和bug报告。
|
||||||
但是,对于多补丁系列,最好避免在回复时使用链接到该系列的旧版本。这样,
|
但是,对于多补丁系列,最好避免在回复时使用链接到该系列的旧版本。这样,
|
||||||
补丁的多个版本就不会成为电子邮件客户端中无法管理的引用序列。如果链接有用,
|
补丁的多个版本就不会成为电子邮件客户端中无法管理的引用树。如果链接有用,
|
||||||
可以使用 https://lore.kernel.org/ 重定向器(例如,在封面电子邮件文本中)
|
可以使用 https://lore.kernel.org/ 重定向器(例如,在封面电子邮件文本中)
|
||||||
链接到补丁系列的早期版本。
|
链接到补丁系列的早期版本。
|
||||||
|
|
||||||
16) 发送git pull请求
|
给出基础树信息
|
||||||
--------------------
|
--------------
|
||||||
|
|
||||||
如果您有一系列补丁,那么让维护人员通过git pull操作将它们直接拉入子系统存储
|
当其他开发人员收到您的补丁并开始审阅时,知道应该将您的工作放到代码树历史记录
|
||||||
库可能是最方便的。但是,请注意,从开发人员那里获取补丁比从邮件列表中获取补
|
中的什么位置通常很有用。这对于自动化持续集成流水(CI)特别有用,这些流水线试
|
||||||
丁需要更高的信任度。因此,许多子系统维护人员不愿意接受请求,特别是来自新的
|
图运行一系列测试,以便在维护人员开始审阅之前确定提交的质量。
|
||||||
未知开发人员的请求。如果有疑问,您可以在封面邮件中使用pull 请求作为补丁系列
|
|
||||||
正常发布的一个选项,让维护人员可以选择使用其中之一。
|
|
||||||
|
|
||||||
pull 请求的主题行中应该有[Git Pull]。请求本身应该在一行中包含存储库名称和
|
如果您使用 ``git format-patch`` 生成补丁,则可以通过 ``--base`` 标志在提交中
|
||||||
感兴趣的分支;它应该看起来像::
|
自动包含基础树信息。使用此选项最简单、最方便的方法是配合主题分支::
|
||||||
|
|
||||||
Please pull from
|
$ git checkout -t -b my-topical-branch master
|
||||||
|
Branch 'my-topical-branch' set up to track local branch 'master'.
|
||||||
|
Switched to a new branch 'my-topical-branch'
|
||||||
|
|
||||||
git://jdelvare.pck.nerim.net/jdelvare-2.6 i2c-for-linus
|
[perform your edits and commits]
|
||||||
|
|
||||||
to get these changes:
|
$ git format-patch --base=auto --cover-letter -o outgoing/ master
|
||||||
|
outgoing/0000-cover-letter.patch
|
||||||
|
outgoing/0001-First-Commit.patch
|
||||||
|
outgoing/...
|
||||||
|
|
||||||
|
当你编辑 ``outgoing/0000-cover-letter.patch`` 时,您会注意到在它的最底部有一
|
||||||
|
行 ``base-commit:`` 尾注,它为审阅者和CI工具提供了足够的信息以正确执行
|
||||||
|
``git am`` 而不必担心冲突::
|
||||||
|
|
||||||
pull 请求还应该包含一条整体消息,说明请求中将包含什么,一个补丁本身的 ``Git shortlog``
|
$ git checkout -b patch-review [base-commit-id]
|
||||||
以及一个显示补丁系列整体效果的 ``diffstat`` 。当然,将所有这些信息收集在一起
|
Switched to a new branch 'patch-review'
|
||||||
的最简单方法是让 ``git`` 使用 ``git request-pull`` 命令为您完成这些工作。
|
$ git am patches.mbox
|
||||||
|
Applying: First Commit
|
||||||
|
Applying: ...
|
||||||
|
|
||||||
一些维护人员(包括Linus)希望看到来自已签名提交的请求;这增加了他们对你的
|
有关此选项的更多信息,请参阅 ``man git-format-patch`` 。
|
||||||
请求信心。特别是,在没有签名标签的情况下,Linus 不会从像 Github 这样的公共
|
|
||||||
托管站点拉请求。
|
|
||||||
|
|
||||||
创建此类签名的第一步是生成一个 GNRPG 密钥,并由一个或多个核心内核开发人员对
|
.. note::
|
||||||
其进行签名。这一步对新开发人员来说可能很困难,但没有办法绕过它。参加会议是
|
|
||||||
找到可以签署您的密钥的开发人员的好方法。
|
|
||||||
|
|
||||||
一旦您在Git 中准备了一个您希望有人拉的补丁系列,就用 ``git tag -s`` 创建一
|
``--base`` 功能是在2.9.0版git中引入的。
|
||||||
个签名标记。这将创建一个新标记,标识该系列中的最后一次提交,并包含用您的私
|
|
||||||
钥创建的签名。您还可以将changelog样式的消息添加到标记中;这是一个描述拉请求
|
|
||||||
整体效果的理想位置。
|
|
||||||
|
|
||||||
如果维护人员将要从中提取的树不是您正在使用的存储库,请不要忘记将已签名的标记
|
如果您不使用git格式化补丁,仍然可以包含相同的 ``base-commit`` 尾注,以指示您
|
||||||
显式推送到公共树。
|
的工作所基于的树的提交哈希。你应该在封面邮件或系列的第一个补丁中添加它,它应
|
||||||
|
该放在 ``---`` 行的下面或所有其他内容之后,即只在你的电子邮件签名之前。
|
||||||
生成拉请求时,请使用已签名的标记作为目标。这样的命令可以实现::
|
|
||||||
|
|
||||||
git request-pull master git://my.public.tree/linux.git my-signed-tag
|
|
||||||
|
|
||||||
参考文献
|
参考文献
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Andrew Morton, "The perfect patch" (tpp).
|
Andrew Morton,“完美的补丁”(tpp)
|
||||||
<https://www.ozlabs.org/~akpm/stuff/tpp.txt>
|
<https://www.ozlabs.org/~akpm/stuff/tpp.txt>
|
||||||
|
|
||||||
Jeff Garzik, "Linux kernel patch submission format".
|
Jeff Garzik,“Linux内核补丁提交格式”
|
||||||
<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
|
<https://web.archive.org/web/20180829112450/http://linux.yyz.us/patch-format.html>
|
||||||
|
|
||||||
Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
|
Greg Kroah-Hartman,“如何惹恼内核子系统维护人员”
|
||||||
<http://www.kroah.com/log/linux/maintainer.html>
|
<http://www.kroah.com/log/linux/maintainer.html>
|
||||||
|
|
||||||
<http://www.kroah.com/log/linux/maintainer-02.html>
|
<http://www.kroah.com/log/linux/maintainer-02.html>
|
||||||
@ -642,16 +643,15 @@ Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
|
|||||||
|
|
||||||
<http://www.kroah.com/log/linux/maintainer-06.html>
|
<http://www.kroah.com/log/linux/maintainer-06.html>
|
||||||
|
|
||||||
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
|
不!!!别再发巨型补丁炸弹给linux-kernel@vger.kernel.org的人们了!
|
||||||
<https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
|
<https://lore.kernel.org/r/20050711.125305.08322243.davem@davemloft.net>
|
||||||
|
|
||||||
Kernel Documentation/process/coding-style.rst:
|
内核 Documentation/translations/zh_CN/process/coding-style.rst
|
||||||
:ref:`Documentation/translations/zh_CN/process/coding-style.rst <cn_codingstyle>`
|
|
||||||
|
|
||||||
Linus Torvalds's mail on the canonical patch format:
|
Linus Torvalds关于标准补丁格式的邮件
|
||||||
<https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
|
<https://lore.kernel.org/r/Pine.LNX.4.58.0504071023190.28951@ppc970.osdl.org>
|
||||||
|
|
||||||
Andi Kleen, "On submitting kernel patches"
|
Andi Kleen,“提交补丁之路”
|
||||||
Some strategies to get difficult or controversial changes in.
|
一些帮助合入困难或有争议的变更的策略。
|
||||||
|
|
||||||
http://halobates.de/on-submitting-patches.pdf
|
http://halobates.de/on-submitting-patches.pdf
|
||||||
|
@ -80,7 +80,7 @@ p->se.vruntime。一旦p->se.vruntime变得足够大,其它的任务将成为
|
|||||||
CFS使用纳秒粒度的计时,不依赖于任何jiffies或HZ的细节。因此CFS并不像之前的调度器那样
|
CFS使用纳秒粒度的计时,不依赖于任何jiffies或HZ的细节。因此CFS并不像之前的调度器那样
|
||||||
有“时间片”的概念,也没有任何启发式的设计。唯一可调的参数(你需要打开CONFIG_SCHED_DEBUG)是:
|
有“时间片”的概念,也没有任何启发式的设计。唯一可调的参数(你需要打开CONFIG_SCHED_DEBUG)是:
|
||||||
|
|
||||||
/proc/sys/kernel/sched_min_granularity_ns
|
/sys/kernel/debug/sched/min_granularity_ns
|
||||||
|
|
||||||
它可以用来将调度器从“桌面”模式(也就是低时延)调节为“服务器”(也就是高批处理)模式。
|
它可以用来将调度器从“桌面”模式(也就是低时延)调节为“服务器”(也就是高批处理)模式。
|
||||||
它的默认设置是适合桌面的工作负载。SCHED_BATCH也被CFS调度器模块处理。
|
它的默认设置是适合桌面的工作负载。SCHED_BATCH也被CFS调度器模块处理。
|
||||||
|
@ -1,212 +0,0 @@
|
|||||||
Chinese translated version of Documentation/admin-guide/bug-hunting.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.
|
|
||||||
|
|
||||||
Traditional Chinese maintainer: Hu Haowen <src.res@email.cn>
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
Documentation/admin-guide/bug-hunting.rst 的繁體中文版翻譯
|
|
||||||
|
|
||||||
如果想評論或更新本文的內容,請直接聯繫原文檔的維護者。如果你使用英文
|
|
||||||
交流有困難的話,也可以向繁體中文版維護者求助。如果本翻譯更新不及時或
|
|
||||||
者翻譯存在問題,請聯繫繁體中文版維護者。
|
|
||||||
|
|
||||||
繁體中文版維護者: 胡皓文 Hu Haowen <src.res@email.cn>
|
|
||||||
繁體中文版翻譯者: 胡皓文 Hu Haowen <src.res@email.cn>
|
|
||||||
繁體中文版校譯者: 胡皓文 Hu Haowen <src.res@email.cn>
|
|
||||||
|
|
||||||
以下爲正文
|
|
||||||
---------------------------------------------------------------------
|
|
||||||
|
|
||||||
注意: ksymoops 在2.6中是沒有用的。 請以原有格式使用Oops(來自dmesg,等等)。
|
|
||||||
忽略任何這樣那樣關於「解碼Oops」或者「通過ksymoops運行」的文檔。 如果你貼出運行過
|
|
||||||
ksymoops的來自2.6的Oops,人們只會讓你重貼一次。
|
|
||||||
|
|
||||||
快速總結
|
|
||||||
-------------
|
|
||||||
|
|
||||||
發現Oops並發送給看似相關的內核領域的維護者。別太擔心對不上號。如果你不確定就發給
|
|
||||||
和你所做的事情相關的代碼的負責人。 如果可重現試著描述怎樣重構。 那甚至比oops更有
|
|
||||||
價值。
|
|
||||||
|
|
||||||
如果你對於發送給誰一無所知, 發給linux-kernel@vger.kernel.org。感謝你幫助Linux
|
|
||||||
儘可能地穩定。
|
|
||||||
|
|
||||||
Oops在哪裡?
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
通常Oops文本由klogd從內核緩衝區里讀取並傳給syslogd,由syslogd寫到syslog文件中,
|
|
||||||
典型地是/var/log/messages(依賴於/etc/syslog.conf)。有時klogd崩潰了,這種情況下你
|
|
||||||
能夠運行dmesg > file來從內核緩衝區中讀取數據並保存下來。 否則你可以
|
|
||||||
cat /proc/kmsg > file, 然而你必須介入中止傳輸, kmsg是一個「永不結束的文件」。如
|
|
||||||
果機器崩潰壞到你不能輸入命令或者磁碟不可用那麼你有三種選擇:-
|
|
||||||
|
|
||||||
(1) 手抄屏幕上的文本待機器重啓後再輸入計算機。 麻煩但如果沒有針對崩潰的準備,
|
|
||||||
這是僅有的選擇。 另外,你可以用數位相機把屏幕拍下來-不太好,但比沒有強。 如果信
|
|
||||||
息滾動到了終端的上面,你會發現以高分辯率啓動(比如,vga=791)會讓你讀到更多的文
|
|
||||||
本。(注意:這需要vesafb,所以對『早期』的oops沒有幫助)
|
|
||||||
|
|
||||||
(2)用串口終端啓動(請參看Documentation/admin-guide/serial-console.rst),運行一個null
|
|
||||||
modem到另一台機器並用你喜歡的通訊工具獲取輸出。Minicom工作地很好。
|
|
||||||
|
|
||||||
(3)使用Kdump(請參看Documentation/admin-guide/kdump/kdump.rst),
|
|
||||||
使用在Documentation/admin-guide/kdump/gdbmacros.txt中定義的dmesg gdb宏,從舊的內存中提取內核
|
|
||||||
環形緩衝區。
|
|
||||||
|
|
||||||
完整信息
|
|
||||||
----------------
|
|
||||||
|
|
||||||
注意:以下來自於Linus的郵件適用於2.4內核。 我因爲歷史原因保留了它,並且因爲其中
|
|
||||||
一些信息仍然適用。 特別注意的是,請忽略任何ksymoops的引用。
|
|
||||||
|
|
||||||
From: Linus Torvalds <torvalds@osdl.org>
|
|
||||||
|
|
||||||
怎樣跟蹤Oops.. [原發到linux-kernel的一封郵件]
|
|
||||||
|
|
||||||
主要的竅門是有五年和這些煩人的oops消息打交道的經驗;-)
|
|
||||||
|
|
||||||
實際上,你有辦法使它更簡單。我有兩個不同的方法:
|
|
||||||
|
|
||||||
gdb /usr/src/linux/vmlinux
|
|
||||||
gdb> disassemble <offending_function>
|
|
||||||
|
|
||||||
那是發現問題的簡單辦法,至少如果bug報告做的好的情況下(象這個一樣-運行ksymoops
|
|
||||||
得到oops發生的函數及函數內的偏移)。
|
|
||||||
|
|
||||||
哦,如果報告發生的內核以相同的編譯器和相似的配置編譯它會有幫助的。
|
|
||||||
|
|
||||||
另一件要做的事是反彙編bug報告的「Code」部分:ksymoops也會用正確的工具來做這件事,
|
|
||||||
但如果沒有那些工具你可以寫一個傻程序:
|
|
||||||
|
|
||||||
char str[] = "\xXX\xXX\xXX...";
|
|
||||||
main(){}
|
|
||||||
|
|
||||||
並用gcc -g編譯它然後執行「disassemble str」(XX部分是由Oops報告的值-你可以僅剪切
|
|
||||||
粘貼並用「\x」替換空格-我就是這麼做的,因爲我懶得寫程序自動做這一切)。
|
|
||||||
|
|
||||||
另外,你可以用scripts/decodecode這個shell腳本。它的使用方法是:
|
|
||||||
decodecode < oops.txt
|
|
||||||
|
|
||||||
「Code」之後的十六進位字節可能(在某些架構上)有一些當前指令之前的指令字節以及
|
|
||||||
當前和之後的指令字節
|
|
||||||
|
|
||||||
Code: f9 0f 8d f9 00 00 00 8d 42 0c e8 dd 26 11 c7 a1 60 ea 2b f9 8b 50 08 a1
|
|
||||||
64 ea 2b f9 8d 34 82 8b 1e 85 db 74 6d 8b 15 60 ea 2b f9 <8b> 43 04 39 42 54
|
|
||||||
7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0
|
|
||||||
|
|
||||||
最後,如果你想知道代碼來自哪裡,你可以:
|
|
||||||
|
|
||||||
cd /usr/src/linux
|
|
||||||
make fs/buffer.s # 或任何產生BUG的文件
|
|
||||||
|
|
||||||
然後你會比gdb反彙編更清楚的知道發生了什麼。
|
|
||||||
|
|
||||||
現在,問題是把你所擁有的所有數據結合起來:C源碼(關於它應該怎樣的一般知識),
|
|
||||||
彙編代碼及其反彙編得到的代碼(另外還有從「oops」消息得到的寄存器狀態-對了解毀壞的
|
|
||||||
指針有用,而且當你有了彙編代碼你也能拿其它的寄存器和任何它們對應的C表達式做匹配
|
|
||||||
)。
|
|
||||||
|
|
||||||
實際上,你僅需看看哪裡不匹配(這個例子是「Code」反彙編和編譯器生成的代碼不匹配)。
|
|
||||||
然後你須要找出爲什麼不匹配。通常很簡單-你看到代碼使用了空指針然後你看代碼想知道
|
|
||||||
空指針是怎麼出現的,還有檢查它是否合法..
|
|
||||||
|
|
||||||
現在,如果明白這是一項耗時的工作而且需要一丁點兒的專心,沒錯。這就是我爲什麼大多
|
|
||||||
只是忽略那些沒有符號表信息的崩潰報告的原因:簡單的說太難查找了(我有一些
|
|
||||||
程序用於在內核代碼段中搜索特定的模式,而且有時我也已經能找出那些崩潰的地方,但是
|
|
||||||
僅僅是找出正確的序列也確實需要相當紮實的內核知識)
|
|
||||||
|
|
||||||
_有時_會發生這種情況,我僅看到崩潰中的反彙編代碼序列, 然後我馬上就明白問題出在
|
|
||||||
哪裡。這時我才意識到自己幹這個工作已經太長時間了;-)
|
|
||||||
|
|
||||||
Linus
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
關於Oops跟蹤的註解:
|
|
||||||
|
|
||||||
爲了幫助Linus和其它內核開發者,klogd納入了大量的支持來處理保護錯誤。爲了擁有對
|
|
||||||
地址解析的完整支持至少應該使用1.3-pl3的sysklogd包。
|
|
||||||
|
|
||||||
當保護錯誤發生時,klogd守護進程自動把內核日誌信息中的重要地址翻譯成它們相應的符
|
|
||||||
號。
|
|
||||||
|
|
||||||
klogd執行兩種類型的地址解析。首先是靜態翻譯其次是動態翻譯。靜態翻譯和ksymoops
|
|
||||||
一樣使用System.map文件。爲了做靜態翻譯klogd守護進程必須在初始化時能找到system
|
|
||||||
map文件。關於klogd怎樣搜索map文件請參看klogd手冊頁。
|
|
||||||
|
|
||||||
動態地址翻譯在使用內核可裝載模塊時很重要。 因爲內核模塊的內存是從內核動態內存池
|
|
||||||
里分配的,所以不管是模塊開始位置還是模塊中函數和符號的位置都不是固定的。
|
|
||||||
|
|
||||||
內核支持允許程序決定裝載哪些模塊和它們在內存中位置的系統調用。使用這些系統調用
|
|
||||||
klogd守護進程生成一張符號表用於調試發生在可裝載模塊中的保護錯誤。
|
|
||||||
|
|
||||||
至少klogd會提供產生保護錯誤的模塊名。還可有額外的符號信息供可裝載模塊開發者選擇
|
|
||||||
以從模塊中輸出符號信息。
|
|
||||||
|
|
||||||
因爲內核模塊環境可能是動態的,所以必須有一種機制當模塊環境發生改變時來通知klogd
|
|
||||||
守護進程。 有一些可用的命令行選項允許klogd向當前執行中的守護進程發送信號,告知符
|
|
||||||
號信息應該被刷新了。 更多信息請參看klogd手冊頁。
|
|
||||||
|
|
||||||
sysklogd發布時包含一個補丁修改了modules-2.0.0包,無論何時一個模塊裝載或者卸載都
|
|
||||||
會自動向klogd發送信號。打上這個補丁提供了必要的對調試發生於內核可裝載模塊的保護
|
|
||||||
錯誤的無縫支持。
|
|
||||||
|
|
||||||
以下是被klogd處理過的發生在可裝載模塊中的一個保護錯誤例子:
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
|
|
||||||
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
|
|
||||||
Aug 29 09:51:01 blizard kernel: *pde = 00000000
|
|
||||||
Aug 29 09:51:01 blizard kernel: Oops: 0002
|
|
||||||
Aug 29 09:51:01 blizard kernel: CPU: 0
|
|
||||||
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
|
|
||||||
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
|
|
||||||
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
|
|
||||||
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
|
|
||||||
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
|
|
||||||
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
|
|
||||||
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
|
|
||||||
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
|
|
||||||
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
|
|
||||||
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
|
|
||||||
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Dr. G.W. Wettstein Oncology Research Div. Computing Facility
|
|
||||||
Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
|
|
||||||
820 4th St. N.
|
|
||||||
Fargo, ND 58122
|
|
||||||
Phone: 701-234-7556
|
|
||||||
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
受汙染的內核
|
|
||||||
|
|
||||||
一些oops報告在程序記數器之後包含字符串'Tainted: '。這表明內核已經被一些東西給汙
|
|
||||||
染了。 該字符串之後緊跟著一系列的位置敏感的字符,每個代表一個特定的汙染值。
|
|
||||||
|
|
||||||
1:'G'如果所有裝載的模塊都有GPL或相容的許可證,'P'如果裝載了任何的專有模塊。
|
|
||||||
沒有模塊MODULE_LICENSE或者帶有insmod認爲是與GPL不相容的的MODULE_LICENSE的模塊被
|
|
||||||
認定是專有的。
|
|
||||||
|
|
||||||
2:'F'如果有任何通過「insmod -f」被強制裝載的模塊,' '如果所有模塊都被正常裝載。
|
|
||||||
|
|
||||||
3:'S'如果oops發生在SMP內核中,運行於沒有證明安全運行多處理器的硬體。 當前這種
|
|
||||||
情況僅限於幾種不支持SMP的速龍處理器。
|
|
||||||
|
|
||||||
4:'R'如果模塊通過「insmod -f」被強制裝載,' '如果所有模塊都被正常裝載。
|
|
||||||
|
|
||||||
5:'M'如果任何處理器報告了機器檢查異常,' '如果沒有發生機器檢查異常。
|
|
||||||
|
|
||||||
6:'B'如果頁釋放函數發現了一個錯誤的頁引用或者一些非預期的頁標誌。
|
|
||||||
|
|
||||||
7:'U'如果用戶或者用戶應用程式特別請求設置汙染標誌,否則' '。
|
|
||||||
|
|
||||||
8:'D'如果內核剛剛死掉,比如有OOPS或者BUG。
|
|
||||||
|
|
||||||
使用'Tainted: '字符串的主要原因是要告訴內核調試者,這是否是一個乾淨的內核亦或發
|
|
||||||
生了任何的不正常的事。汙染是永久的:即使出錯的模塊已經被卸載了,汙染值仍然存在,
|
|
||||||
以表明內核不再值得信任。
|
|
||||||
|
|
@ -377,7 +377,7 @@ Emulating cr0.wp
|
|||||||
================
|
================
|
||||||
|
|
||||||
If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
|
If tdp is not enabled, the host must keep cr0.wp=1 so page write protection
|
||||||
works for the guest kernel, not guest guest userspace. When the guest
|
works for the guest kernel, not guest userspace. When the guest
|
||||||
cr0.wp=1, this does not present a problem. However when the guest cr0.wp=0,
|
cr0.wp=1, this does not present a problem. However when the guest cr0.wp=0,
|
||||||
we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
|
we cannot map the permissions for gpte.u=1, gpte.w=0 to any spte (the
|
||||||
semantics require allowing any guest kernel access plus user read access).
|
semantics require allowing any guest kernel access plus user read access).
|
||||||
|
@ -52,7 +52,7 @@ Notes and limitations.
|
|||||||
clear the entire bulk in buffer. It would be possible to read the
|
clear the entire bulk in buffer. It would be possible to read the
|
||||||
maximum buffer size to not run into this error condition, only extra
|
maximum buffer size to not run into this error condition, only extra
|
||||||
bytes in the buffer is a logic error in the driver. The code should
|
bytes in the buffer is a logic error in the driver. The code should
|
||||||
should match reads and writes as well as data sizes. Reads and
|
match reads and writes as well as data sizes. Reads and
|
||||||
writes are serialized and the status verifies that the chip is idle
|
writes are serialized and the status verifies that the chip is idle
|
||||||
(and data is available) before the read is executed, so it should
|
(and data is available) before the read is executed, so it should
|
||||||
not happen.
|
not happen.
|
||||||
|
@ -113,7 +113,7 @@ generally only make sense when searching is disabled, as a search will
|
|||||||
redetect manually removed devices that are present and timeout manually
|
redetect manually removed devices that are present and timeout manually
|
||||||
added devices that aren't on the bus.
|
added devices that aren't on the bus.
|
||||||
|
|
||||||
Bus searches occur at an interval, specified as a summ of timeout and
|
Bus searches occur at an interval, specified as a sum of timeout and
|
||||||
timeout_us module parameters (either of which may be 0) for as long as
|
timeout_us module parameters (either of which may be 0) for as long as
|
||||||
w1_master_search remains greater than 0 or is -1. Each search attempt
|
w1_master_search remains greater than 0 or is -1. Each search attempt
|
||||||
decrements w1_master_search by 1 (down to 0) and increments
|
decrements w1_master_search by 1 (down to 0) and increments
|
||||||
|
@ -33,8 +33,8 @@ Some of these entries are:
|
|||||||
- interrupt: An array of entries. Every IDT vector that doesn't
|
- interrupt: An array of entries. Every IDT vector that doesn't
|
||||||
explicitly point somewhere else gets set to the corresponding
|
explicitly point somewhere else gets set to the corresponding
|
||||||
value in interrupts. These point to a whole array of
|
value in interrupts. These point to a whole array of
|
||||||
magically-generated functions that make their way to do_IRQ with
|
magically-generated functions that make their way to common_interrupt()
|
||||||
the interrupt number as a parameter.
|
with the interrupt number as a parameter.
|
||||||
|
|
||||||
- APIC interrupts: Various special-purpose interrupts for things
|
- APIC interrupts: Various special-purpose interrupts for things
|
||||||
like TLB shootdown.
|
like TLB shootdown.
|
||||||
|
@ -3751,7 +3751,7 @@ sub process {
|
|||||||
if ($realfile =~ /\.S$/ &&
|
if ($realfile =~ /\.S$/ &&
|
||||||
$line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) {
|
$line =~ /^\+\s*(?:[A-Z]+_)?SYM_[A-Z]+_(?:START|END)(?:_[A-Z_]+)?\s*\(\s*\.L/) {
|
||||||
WARN("AVOID_L_PREFIX",
|
WARN("AVOID_L_PREFIX",
|
||||||
"Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/asm-annotations.rst\n" . $herecurr);
|
"Avoid using '.L' prefixed local symbol names for denoting a range of code via 'SYM_*_START/END' annotations; see Documentation/core-api/asm-annotations.rst\n" . $herecurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
# check we are in a valid source file C or perl if not then ignore this hunk
|
# check we are in a valid source file C or perl if not then ignore this hunk
|
||||||
@ -4695,12 +4695,12 @@ sub process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# avoid BUG() or BUG_ON()
|
# do not use BUG() or variants
|
||||||
if ($line =~ /\b(?:BUG|BUG_ON)\b/) {
|
if ($line =~ /\b(?!AA_|BUILD_|DCCP_|IDA_|KVM_|RWLOCK_|snd_|SPIN_)(?:[a-zA-Z_]*_)?BUG(?:_ON)?(?:_[A-Z_]+)?\s*\(/) {
|
||||||
my $msg_level = \&WARN;
|
my $msg_level = \&WARN;
|
||||||
$msg_level = \&CHK if ($file);
|
$msg_level = \&CHK if ($file);
|
||||||
&{$msg_level}("AVOID_BUG",
|
&{$msg_level}("AVOID_BUG",
|
||||||
"Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr);
|
"Do not crash the kernel unless it is absolutely unavoidable--use WARN_ON_ONCE() plus recovery code (if feasible) instead of BUG() or variants\n" . $herecurr);
|
||||||
}
|
}
|
||||||
|
|
||||||
# avoid LINUX_VERSION_CODE
|
# avoid LINUX_VERSION_CODE
|
||||||
|
Loading…
Reference in New Issue
Block a user