code:
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst

:Original: Documentation/admin-guide/mm/damon/usage.rst

:翻译:

 司延腾 Yanteng Si <siyanteng@loongson.cn>

:校译:

========
详细用法
========

DAMON 为不同的用户提供了下面这些接口。

- *DAMON用户空间工具。*
  `这 <https://github.com/awslabs/damo>`_ 为有这特权的人， 如系统管理员，希望有一个刚好
  可以工作的人性化界面。
  使用它，用户可以以人性化的方式使用DAMON的主要功能。不过，它可能不会为特殊情况进行高度调整。
  它同时支持虚拟和物理地址空间的监测。更多细节，请参考它的 `使用文档
  <https://github.com/awslabs/damo/blob/next/USAGE.md>`_。
- *sysfs接口。*
  :ref:`这 <sysfs_interface>` 是为那些希望更高级的使用DAMON的特权用户空间程序员准备的。
  使用它，用户可以通过读取和写入特殊的sysfs文件来使用DAMON的主要功能。因此，你可以编写和使
  用你个性化的DAMON sysfs包装程序，代替你读/写sysfs文件。  `DAMON用户空间工具
  <https://github.com/awslabs/damo>`_ 就是这种程序的一个例子  它同时支持虚拟和物理地址
  空间的监测。注意，这个界面只提供简单的监测结果 :ref:`统计 <damos_stats>`。对于详细的监测
  结果，DAMON提供了一个:ref:`跟踪点 <tracepoint>`。
- *debugfs interface.*
  :ref:`这 <debugfs_interface>` 几乎与:ref:`sysfs interface <sysfs_interface>` 接
  口相同。这将在下一个LTS内核发布后被移除，所以用户应该转移到
  :ref:`sysfs interface <sysfs_interface>`。
- *内核空间编程接口。*
  :doc:`这 </mm/damon/api>` 这是为内核空间程序员准备的。使用它，用户可以通过为你编写内
  核空间的DAMON应用程序，最灵活有效地利用DAMON的每一个功能。你甚至可以为各种地址空间扩展DAMON。
  详细情况请参考接口 :doc:`文件 </mm/damon/api>`。

sysfs接口
=========
DAMON的sysfs接口是在定义 ``CONFIG_DAMON_SYSFS`` 时建立的。它在其sysfs目录下创建多
个目录和文件， ``<sysfs>/kernel/mm/damon/`` 。你可以通过对该目录下的文件进行写入和
读取来控制DAMON。

对于一个简短的例子，用户可以监测一个给定工作负载的虚拟地址空间，如下所示::

    # cd /sys/kernel/mm/damon/admin/
    # echo 1 > kdamonds/nr && echo 1 > kdamonds/0/contexts/nr
    # echo vaddr > kdamonds/0/contexts/0/operations
    # echo 1 > kdamonds/0/contexts/0/targets/nr
    # echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid
    # echo on > kdamonds/0/state

文件层次结构
------------

DAMON sysfs接口的文件层次结构如下图所示。在下图中，父子关系用缩进表示，每个目录有
``/`` 后缀，每个目录中的文件用逗号（","）分开。 ::

    /sys/kernel/mm/damon/admin
    │ kdamonds/nr_kdamonds
    │ │ 0/state,pid
    │ │ │ contexts/nr_contexts
    │ │ │ │ 0/operations
    │ │ │ │ │ monitoring_attrs/
    │ │ │ │ │ │ intervals/sample_us,aggr_us,update_us
    │ │ │ │ │ │ nr_regions/min,max
    │ │ │ │ │ targets/nr_targets
    │ │ │ │ │ │ 0/pid_target
    │ │ │ │ │ │ │ regions/nr_regions
    │ │ │ │ │ │ │ │ 0/start,end
    │ │ │ │ │ │ │ │ ...
    │ │ │ │ │ │ ...
    │ │ │ │ │ schemes/nr_schemes
    │ │ │ │ │ │ 0/action
    │ │ │ │ │ │ │ access_pattern/
    │ │ │ │ │ │ │ │ sz/min,max
    │ │ │ │ │ │ │ │ nr_accesses/min,max
    │ │ │ │ │ │ │ │ age/min,max
    │ │ │ │ │ │ │ quotas/ms,bytes,reset_interval_ms
    │ │ │ │ │ │ │ │ weights/sz_permil,nr_accesses_permil,age_permil
    │ │ │ │ │ │ │ watermarks/metric,interval_us,high,mid,low
    │ │ │ │ │ │ │ stats/nr_tried,sz_tried,nr_applied,sz_applied,qt_exceeds
    │ │ │ │ │ │ ...
    │ │ │ │ ...
    │ │ ...

根
--

DAMON sysfs接口的根是 ``<sysfs>/kernel/mm/damon/`` ，它有一个名为 ``admin`` 的
目录。该目录包含特权用户空间程序控制DAMON的文件。拥有根权限的用户空间工具或deamons可以
使用这个目录。

kdamonds/
---------

与监测相关的信息包括请求规格和结果被称为DAMON上下文。DAMON用一个叫做kdamond的内核线程
执行每个上下文，多个kdamonds可以并行运行。

在 ``admin`` 目录下，有一个目录，即``kdamonds``，它有控制kdamonds的文件存在。在开始
时，这个目录只有一个文件，``nr_kdamonds``。向该文件写入一个数字（``N``），就会创建名为
``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个kdamond。

kdamonds/<N>/
-------------

在每个kdamond目录中，存在两个文件（``state`` 和 ``pid`` ）和一个目录( ``contexts`` )。

读取 ``state`` 时，如果kdamond当前正在运行，则返回 ``on`` ，如果没有运行则返回 ``off`` 。
写入 ``on`` 或 ``off`` 使kdamond处于状态。向 ``state`` 文件写 ``update_schemes_stats`` ，
更新kdamond的每个基于DAMON的操作方案的统计文件的内容。关于统计信息的细节，请参考
:ref:`stats section <sysfs_schemes_stats>`.

如果状态为 ``on``，读取 ``pid`` 显示kdamond线程的pid。

``contexts`` 目录包含控制这个kdamond要执行的监测上下文的文件。

kdamonds/<N>/contexts/
----------------------

在开始时，这个目录只有一个文件，即 ``nr_contexts`` 。向该文件写入一个数字( ``N`` )，就会创
建名为``0`` 到 ``N-1`` 的子目录数量。每个目录代表每个监测背景。目前，每个kdamond只支持
一个上下文，所以只有 ``0`` 或 ``1`` 可以被写入文件。

contexts/<N>/
-------------

在每个上下文目录中，存在一个文件(``operations``)和三个目录(``monitoring_attrs``,
``targets``, 和 ``schemes``)。

DAMON支持多种类型的监测操作，包括对虚拟地址空间和物理地址空间的监测。你可以通过向文件
中写入以下关键词之一，并从文件中读取，来设置和获取DAMON将为上下文使用何种类型的监测操作。

 - vaddr: 监测特定进程的虚拟地址空间
 - paddr: 监视系统的物理地址空间

contexts/<N>/monitoring_attrs/
------------------------------

用于指定监测属性的文件，包括所需的监测质量和效率，都在 ``monitoring_attrs`` 目录中。
具体来说，这个目录下有两个目录，即 ``intervals`` 和 ``nr_regions`` 。

在 ``intervals`` 目录下，存在DAMON的采样间隔(``sample_us``)、聚集间隔(``aggr_us``)
和更新间隔(``update_us``)三个文件。你可以通过写入和读出这些文件来设置和获取微秒级的值。

在 ``nr_regions`` 目录下，有两个文件分别用于DAMON监测区域的下限和上限（``min`` 和 ``max`` ），
这两个文件控制着监测的开销。你可以通过向这些文件的写入和读出来设置和获取这些值。

关于间隔和监测区域范围的更多细节，请参考设计文件 (:doc:`/mm/damon/design`)。

contexts/<N>/targets/
---------------------

在开始时，这个目录只有一个文件 ``nr_targets`` 。向该文件写入一个数字(``N``)，就可以创建
名为 ``0`` 到 ``N-1`` 的子目录的数量。每个目录代表每个监测目标。

targets/<N>/
------------

在每个目标目录中，存在一个文件(``pid_target``)和一个目录(``regions``)。

如果你把 ``vaddr`` 写到 ``contexts/<N>/operations`` 中，每个目标应该是一个进程。你
可以通过将进程的pid写到 ``pid_target`` 文件中来指定DAMON的进程。

targets/<N>/regions
-------------------

当使用 ``vaddr`` 监测操作集时（ ``vaddr`` 被写入 ``contexts/<N>/operations`` 文
件），DAMON自动设置和更新监测目标区域，这样就可以覆盖目标进程的整个内存映射。然而，用户可
能希望将初始监测区域设置为特定的地址范围。

相反，当使用 ``paddr`` 监测操作集时，DAMON不会自动设置和更新监测目标区域（ ``paddr``
被写入 ``contexts/<N>/operations`` 中）。因此，在这种情况下，用户应该自己设置监测目标
区域。

在这种情况下，用户可以按照自己的意愿明确设置初始监测目标区域，将适当的值写入该目录下的文件。

开始时，这个目录只有一个文件， ``nr_regions`` 。向该文件写入一个数字(``N``)，就可以创
建名为 ``0`` 到  ``N-1`` 的子目录。每个目录代表每个初始监测目标区域。

regions/<N>/
------------

在每个区域目录中，你会发现两个文件（ ``start``  和  ``end`` ）。你可以通过向文件写入
和从文件中读出，分别设置和获得初始监测目标区域的起始和结束地址。

contexts/<N>/schemes/
---------------------

对于一版的基于DAMON的数据访问感知的内存管理优化，用户通常希望系统对特定访问模式的内存区
域应用内存管理操作。DAMON从用户那里接收这种形式化的操作方案，并将这些方案应用于目标内存
区域。用户可以通过读取和写入这个目录下的文件来获得和设置这些方案。

在开始时，这个目录只有一个文件，``nr_schemes``。向该文件写入一个数字(``N``)，就可以
创建名为``0``到``N-1``的子目录的数量。每个目录代表每个基于DAMON的操作方案。

schemes/<N>/
------------

在每个方案目录中，存在四个目录(``access_pattern``, ``quotas``,``watermarks``,
和 ``stats``)和一个文件(``action``)。

``action`` 文件用于设置和获取你想应用于具有特定访问模式的内存区域的动作。可以写入文件
和从文件中读取的关键词及其含义如下。

 - ``willneed``: 对有 ``MADV_WILLNEED`` 的区域调用 ``madvise()`` 。
 - ``cold``: 对具有 ``MADV_COLD`` 的区域调用 ``madvise()`` 。
 - ``pageout``: 为具有 ``MADV_PAGEOUT`` 的区域调用 ``madvise()`` 。
 - ``hugepage``: 为带有 ``MADV_HUGEPAGE`` 的区域调用 ``madvise()`` 。
 - ``nohugepage``: 为带有 ``MADV_NOHUGEPAGE`` 的区域调用 ``madvise()``。
 - ``lru_prio``: 在其LRU列表上对区域进行优先排序。
 - ``lru_deprio``: 对区域的LRU列表进行降低优先处理。
 - ``stat``: 什么都不做，只计算统计数据

schemes/<N>/access_pattern/
---------------------------

每个基于DAMON的操作方案的目标访问模式由三个范围构成，包括以字节为单位的区域大小、每个
聚合区间的监测访问次数和区域年龄的聚合区间数。

在 ``access_pattern`` 目录下，存在三个目录（ ``sz``, ``nr_accesses``, 和 ``age`` ），
每个目录有两个文件（``min`` 和 ``max`` ）。你可以通过向  ``sz``, ``nr_accesses``, 和
``age``  目录下的 ``min`` 和 ``max`` 文件分别写入和读取来设置和获取给定方案的访问模式。

schemes/<N>/quotas/
-------------------

每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载，所以不容易找到。更糟糕的是，将某些动作
的方案设置得过于激进会造成严重的开销。为了避免这种开销，用户可以为每个方案限制时间和大小配额。
具体来说，用户可以要求DAMON尽量只使用特定的时间（``时间配额``）来应用行动，并且在给定的时间间
隔（``重置间隔``）内，只对具有目标访问模式的内存区域应用行动，而不使用特定数量（``大小配额``）。

当预计超过配额限制时，DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄，对找到的内存区域
进行优先排序。为了进行个性化的优先排序，用户可以为这三个属性设置权重。

在 ``quotas`` 目录下，存在三个文件（``ms``, ``bytes``, ``reset_interval_ms``）和一个
目录(``weights``)，其中有三个文件(``sz_permil``, ``nr_accesses_permil``, 和
``age_permil``)。

你可以设置以毫秒为单位的 ``时间配额`` ，以字节为单位的 ``大小配额`` ，以及以毫秒为单位的 ``重
置间隔`` ，分别向这三个文件写入数值。你还可以通过向 ``weights`` 目录下的三个文件写入数值来设
置大小、访问频率和年龄的优先权，单位为千分之一。

schemes/<N>/watermarks/
-----------------------

为了便于根据系统状态激活和停用每个方案，DAMON提供了一个称为水位的功能。该功能接收五个值，称为
``度量`` 、``间隔`` 、``高`` 、``中`` 、``低`` 。``度量值`` 是指可以测量的系统度量值，如
自由内存比率。如果系统的度量值 ``高`` 于memoent的高值或 ``低`` 于低值，则该方案被停用。如果
该值低于 ``中`` ，则该方案被激活。

在水位目录下，存在五个文件(``metric``, ``interval_us``,``high``, ``mid``, and ``low``)
用于设置每个值。你可以通过向这些文件的写入来分别设置和获取这五个值。

可以写入 ``metric`` 文件的关键词和含义如下。

 - none: 忽略水位
 - free_mem_rate: 系统的自由内存率（千分比）。

``interval`` 应以微秒为单位写入。

schemes/<N>/stats/
------------------

DAMON统计每个方案被尝试应用的区域的总数量和字节数，每个方案被成功应用的区域的两个数字，以及
超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。

可以通过读取 ``stats`` 目录下的文件(``nr_tried``, ``sz_tried``, ``nr_applied``,
``sz_applied``, 和 ``qt_exceeds``)）分别检索这些统计数据。这些文件不是实时更新的，所以
你应该要求DAMON sysfs接口通过在相关的 ``kdamonds/<N>/state`` 文件中写入一个特殊的关键字
``update_schemes_stats`` 来更新统计信息的文件内容。

用例
~~~~

下面的命令应用了一个方案：”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间间隔内
显示出每一个聚合时间间隔[0, 5]的访问量，请分页该区域。对于分页，每秒最多只能使用10ms，而且每
秒分页不能超过1GiB。在这一限制下，首先分页出具有较长年龄的内存区域。另外，每5秒钟检查一次系统
的可用内存率，当可用内存率低于50%时开始监测和分页，但如果可用内存率大于60%，或低于30%，则停
止监测。“ ::

    # cd <sysfs>/kernel/mm/damon/admin
    # # populate directories
    # echo 1 > kdamonds/nr_kdamonds; echo 1 > kdamonds/0/contexts/nr_contexts;
    # echo 1 > kdamonds/0/contexts/0/schemes/nr_schemes
    # cd kdamonds/0/contexts/0/schemes/0
    # # set the basic access pattern and the action
    # echo 4096 > access_patterns/sz/min
    # echo 8192 > access_patterns/sz/max
    # echo 0 > access_patterns/nr_accesses/min
    # echo 5 > access_patterns/nr_accesses/max
    # echo 10 > access_patterns/age/min
    # echo 20 > access_patterns/age/max
    # echo pageout > action
    # # set quotas
    # echo 10 > quotas/ms
    # echo $((1024*1024*1024)) > quotas/bytes
    # echo 1000 > quotas/reset_interval_ms
    # # set watermark
    # echo free_mem_rate > watermarks/metric
    # echo 5000000 > watermarks/interval_us
    # echo 600 > watermarks/high
    # echo 500 > watermarks/mid
    # echo 300 > watermarks/low

请注意，我们强烈建议使用用户空间的工具，如 `damo <https://github.com/awslabs/damo>`_ ，
而不是像上面那样手动读写文件。以上只是一个例子。

debugfs接口
===========

DAMON导出了八个文件, ``attrs``, ``target_ids``, ``init_regions``,
``schemes``, ``monitor_on``, ``kdamond_pid``, ``mk_contexts`` 和
``rm_contexts`` under its debugfs directory, ``<debugfs>/damon/``.

属性
----

用户可以通过读取和写入 ``attrs`` 文件获得和设置 ``采样间隔`` 、 ``聚集间隔`` 、 ``更新间隔``
以及监测目标区域的最小/最大数量。要详细了解监测属性，请参考 `:doc:/mm/damon/design` 。例如，
下面的命令将这些值设置为5ms、100ms、1000ms、10和1000，然后再次检查::

    # cd <debugfs>/damon
    # echo 5000 100000 1000000 10 1000 > attrs
    # cat attrs
    5000 100000 1000000 10 1000

目标ID
------

一些类型的地址空间支持多个监测目标。例如，虚拟内存地址空间的监测可以有多个进程作为监测目标。用户
可以通过写入目标的相关id值来设置目标，并通过读取 ``target_ids`` 文件来获得当前目标的id。在监
测虚拟地址空间的情况下，这些值应该是监测目标进程的pid。例如，下面的命令将pid为42和4242的进程设
为监测目标，并再次检查::

    # cd <debugfs>/damon
    # echo 42 4242 > target_ids
    # cat target_ids
    42 4242

用户还可以通过在文件中写入一个特殊的关键字 "paddr\n" 来监测系统的物理内存地址空间。因为物理地
址空间监测不支持多个目标，读取文件会显示一个假值，即 ``42`` ，如下图所示::

    # cd <debugfs>/damon
    # echo paddr > target_ids
    # cat target_ids
    42

请注意，设置目标ID并不启动监测。

初始监测目标区域
----------------

在虚拟地址空间监测的情况下，DAMON自动设置和更新监测的目标区域，这样就可以覆盖目标进程的整个
内存映射。然而，用户可能希望将监测区域限制在特定的地址范围内，如堆、栈或特定的文件映射区域。
或者，一些用户可以知道他们工作负载的初始访问模式，因此希望为“自适应区域调整”设置最佳初始区域。

相比之下，DAMON在物理内存监测的情况下不会自动设置和更新监测目标区域。因此，用户应该自己设置
监测目标区域。

在这种情况下，用户可以通过在 ``init_regions`` 文件中写入适当的值，明确地设置他们想要的初
始监测目标区域。输入的每一行应代表一个区域，形式如下::

    <target idx> <start address> <end address>

目标idx应该是 ``target_ids`` 文件中目标的索引，从 ``0`` 开始，区域应该按照地址顺序传递。
例如，下面的命令将设置几个地址范围， ``1-100`` 和 ``100-200`` 作为pid 42的初始监测目标
区域，这是 ``target_ids`` 中的第一个（索引 ``0`` ），另外几个地址范围， ``20-40`` 和
``50-100`` 作为pid 4242的地址，这是 ``target_ids`` 中的第二个（索引 ``1`` ）::

    # cd <debugfs>/damon
    # cat target_ids
    42 4242
    # echo "0   1       100
            0   100     200
            1   20      40
            1   50      100" > init_regions

请注意，这只是设置了初始的监测目标区域。在虚拟内存监测的情况下，DAMON会在一个 ``更新间隔``
后自动更新区域的边界。因此，在这种情况下，如果用户不希望更新的话，应该把 ``更新间隔`` 设
置得足够大。

方案
----

对于通常的基于DAMON的数据访问感知的内存管理优化，用户只是希望系统对特定访问模式的内存区域应用内
存管理操作。DAMON从用户那里接收这种形式化的操作方案，并将这些方案应用到目标进程中。

用户可以通过读取和写入 ``scheme`` debugfs文件来获得和设置这些方案。读取该文件还可以显示每个
方案的统计数据。在文件中，每一个方案都应该在每一行中以下列形式表示出来::

    <target access pattern> <action> <quota> <watermarks>

你可以通过简单地在文件中写入一个空字符串来禁用方案。

目标访问模式
~~~~~~~~~~~~

``<目标访问模式>`` 是由三个范围构成的，形式如下::

    min-size max-size min-acc max-acc min-age max-age

具体来说，区域大小的字节数（ `min-size` 和 `max-size` ），访问频率的每聚合区间的监测访问次
数（ `min-acc` 和 `max-acc` ），区域年龄的聚合区间数（ `min-age` 和 `max-age` ）都被指定。
请注意，这些范围是封闭区间。

动作
~~~~

``<action>`` 是一个预定义的内存管理动作的整数，DAMON将应用于具有目标访问模式的区域。支持
的数字和它们的含义如下::

 - 0: Call ``madvise()`` for the region with ``MADV_WILLNEED``
 - 1: Call ``madvise()`` for the region with ``MADV_COLD``
 - 2: Call ``madvise()`` for the region with ``MADV_PAGEOUT``
 - 3: Call ``madvise()`` for the region with ``MADV_HUGEPAGE``
 - 4: Call ``madvise()`` for the region with ``MADV_NOHUGEPAGE``
 - 5: Do nothing but count the statistics

配额
~~~~

每个 ``动作`` 的最佳 ``目标访问模式`` 取决于工作负载，所以不容易找到。更糟糕的是，将某个
动作的方案设置得过于激进会导致严重的开销。为了避免这种开销，用户可以通过下面表格中的 ``<quota>``
来限制方案的时间和大小配额::

    <ms> <sz> <reset interval> <priority weights>

这使得DAMON在 ``<reset interval>`` 毫秒内，尽量只用 ``<ms>`` 毫秒的时间对 ``目标访
问模式`` 的内存区域应用动作，并在 ``<reset interval>`` 内只对最多<sz>字节的内存区域应
用动作。将 ``<ms>`` 和 ``<sz>`` 都设置为零，可以禁用配额限制。

当预计超过配额限制时，DAMON会根据 ``目标访问模式`` 的大小、访问频率和年龄，对发现的内存
区域进行优先排序。为了实现个性化的优先级，用户可以在 ``<优先级权重>`` 中设置这三个属性的
权重，具体形式如下::

    <size weight> <access frequency weight> <age weight>

水位
~~~~

有些方案需要根据系统特定指标的当前值来运行，如自由内存比率。对于这种情况，用户可以为该条
件指定水位。::

    <metric> <check interval> <high mark> <middle mark> <low mark>

``<metric>`` 是一个预定义的整数，用于要检查的度量。支持的数字和它们的含义如下。

 - 0: 忽视水位
 - 1: 系统空闲内存率 (千分比)

每隔 ``<检查间隔>`` 微秒检查一次公制的值。

如果该值高于 ``<高标>`` 或低于 ``<低标>`` ，该方案被停用。如果该值低于 ``<中标>`` ，
该方案将被激活。

统计数据
~~~~~~~~

它还统计每个方案被尝试应用的区域的总数量和字节数，每个方案被成功应用的区域的两个数量，以
及超过配额限制的总数量。这些统计数据可用于在线分析或调整方案。

统计数据可以通过读取方案文件来显示。读取该文件将显示你在每一行中输入的每个 ``方案`` ，
统计的五个数字将被加在每一行的末尾。

例子
~~~~

下面的命令应用了一个方案：”如果一个大小为[4KiB, 8KiB]的内存区域在[10, 20]的聚合时间
间隔内显示出每一个聚合时间间隔[0, 5]的访问量，请分页出该区域。对于分页，每秒最多只能使
用10ms，而且每秒分页不能超过1GiB。在这一限制下，首先分页出具有较长年龄的内存区域。另外，
每5秒钟检查一次系统的可用内存率，当可用内存率低于50%时开始监测和分页，但如果可用内存率
大于60%，或低于30%，则停止监测“::

    # cd <debugfs>/damon
    # scheme="4096 8192  0 5    10 20    2"  # target access pattern and action
    # scheme+=" 10 $((1024*1024*1024)) 1000" # quotas
    # scheme+=" 0 0 100"                     # prioritization weights
    # scheme+=" 1 5000000 600 500 300"       # watermarks
    # echo "$scheme" > schemes

开关
----

除非你明确地启动监测，否则如上所述的文件设置不会产生效果。你可以通过写入和读取 ``monitor_on``
文件来启动、停止和检查监测的当前状态。写入 ``on`` 该文件可以启动对有属性的目标的监测。写入
``off`` 该文件则停止这些目标。如果每个目标进程被终止，DAMON也会停止。下面的示例命令开启、关
闭和检查DAMON的状态::

    # cd <debugfs>/damon
    # echo on > monitor_on
    # echo off > monitor_on
    # cat monitor_on
    off

请注意，当监测开启时，你不能写到上述的debugfs文件。如果你在DAMON运行时写到这些文件，将会返
回一个错误代码，如 ``-EBUSY`` 。

监测线程PID
-----------

DAMON通过一个叫做kdamond的内核线程来进行请求监测。你可以通过读取 ``kdamond_pid`` 文件获
得该线程的 ``pid`` 。当监测被 ``关闭`` 时，读取该文件不会返回任何信息::

    # cd <debugfs>/damon
    # cat monitor_on
    off
    # cat kdamond_pid
    none
    # echo on > monitor_on
    # cat kdamond_pid
    18594

使用多个监测线程
----------------

每个监测上下文都会创建一个 ``kdamond`` 线程。你可以使用 ``mk_contexts`` 和 ``rm_contexts``
文件为多个 ``kdamond`` 需要的用例创建和删除监测上下文。

将新上下文的名称写入 ``mk_contexts`` 文件，在 ``DAMON debugfs`` 目录上创建一个该名称的目录。
该目录将有该上下文的 ``DAMON debugfs`` 文件::

    # cd <debugfs>/damon
    # ls foo
    # ls: cannot access 'foo': No such file or directory
    # echo foo > mk_contexts
    # ls foo
    # attrs  init_regions  kdamond_pid  schemes  target_ids

如果不再需要上下文，你可以通过把上下文的名字放到 ``rm_contexts`` 文件中来删除它和相应的目录::

    # echo foo > rm_contexts
    # ls foo
    # ls: cannot access 'foo': No such file or directory

注意， ``mk_contexts`` 、 ``rm_contexts`` 和 ``monitor_on`` 文件只在根目录下。

监测结果的监测点
================

DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果.  当监测开启时，你可
以记录追踪点事件，并使用追踪点支持工具如perf显示结果。比如说::

    # echo on > monitor_on
    # perf record -e damon:damon_aggregated &
    # sleep 5
    # kill 9 $(pidof perf)
    # echo off > monitor_on
    # perf script


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

:Original:   Documentation/admin-guide/mm/index.rst

:翻译:

  徐鑫 xu xin <xu.xin16@zte.com.cn>

========
内存管理
========

Linux内存管理子系统，顾名思义，是负责系统中的内存管理。它包括了虚拟内存与请求
分页的实现，内核内部结构和用户空间程序的内存分配、将文件映射到进程地址空间以
及许多其他很酷的事情。

Linux内存管理是一个具有许多可配置设置的复杂系统, 且这些设置中的大多数都可以通
过 ``/proc`` 文件系统获得，并且可以使用 ``sysctl`` 进行查询和调整。这些API接
口被描述在Documentation/admin-guide/sysctl/vm.rst文件和 `man 5 proc`_ 中。

.. _man 5 proc: http://man7.org/linux/man-pages/man5/proc.5.html

Linux内存管理有它自己的术语，如果你还不熟悉它，请考虑阅读下面参考：
:ref:`Documentation/admin-guide/mm/concepts.rst <mm_concepts>`.

在此目录下，我们详细描述了如何与Linux内存管理中的各种机制交互。

.. toctree::
   :maxdepth: 1

   damon/index
   ksm

Todolist:
* concepts
* cma_debugfs
* hugetlbpage
* idle_page_tracking
* memory-hotplug
* nommu-mmap
* numa_memory_policy
* numaperf
* pagemap
* soft-dirty
* swap_numa
* transhuge
* userfaultfd
* zswap

repo_name: angery/linux


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

:Original: Documentation/admin-guide/mm/ksm.rst

:翻译:

  徐鑫 xu xin <xu.xin16@zte.com.cn>

============
内核同页合并
============

概述
====

KSM是一种能节省内存的数据去重功能，由CONFIG_KSM=y启用，并在2.6.32版本时被添
加到Linux内核。详见 ``mm/ksm.c`` 的实现，以及http://lwn.net/Articles/306704
和https://lwn.net/Articles/330589

KSM最初目的是为了与KVM（即著名的内核共享内存）一起使用而开发的，通过共享虚拟机
之间的公共数据，将更多虚拟机放入物理内存。但它对于任何会生成多个相同数据实例的
应用程序都是很有用的。

KSM的守护进程ksmd会定期扫描那些已注册的用户内存区域，查找内容相同的页面，这些
页面可以被单个写保护页面替换（如果进程以后想要更新其内容，将自动复制）。使用：
引用:`sysfs intraface  <ksm_sysfs>` 接口来配置KSM守护程序在单个过程中所扫描的页
数以及两个过程之间的间隔时间。

KSM只合并匿名（私有）页面，从不合并页缓存（文件）页面。KSM的合并页面最初只能被
锁定在内核内存中，但现在可以就像其他用户页面一样被换出（但当它们被交换回来时共
享会被破坏: ksmd必须重新发现它们的身份并再次合并）。

以madvise控制KSM
================

KSM仅在特定的地址空间区域时运行，即应用程序通过使用如下所示的madvise(2)系统调
用来请求某块地址成为可能的合并候选者的地址空间::

    int madvise(addr, length, MADV_MERGEABLE)

应用程序当然也可以通过调用::

    int madvise(addr, length, MADV_UNMERGEABLE)

来取消该请求，并恢复为非共享页面：此时KSM将去除合并在该范围内的任何合并页。注意：
这个去除合并的调用可能突然需要的内存量超过实际可用的内存量-那么可能会出现EAGAIN
失败，但更可能会唤醒OOM killer。

如果KSM未被配置到正在运行的内核中，则madvise MADV_MERGEABLE 和 MADV_UNMERGEABLE
的调用只会以EINVAL 失败。如果正在运行的内核是用CONFIG_KSM=y方式构建的，那么这些
调用通常会成功：即使KSM守护程序当前没有运行，MADV_MERGEABLE 仍然会在KSM守护程序
启动时注册范围，即使该范围不能包含KSM实际可以合并的任何页面，即使MADV_UNMERGEABLE
应用于从未标记为MADV_MERGEABLE的范围。

如果一块内存区域必须被拆分为至少一个新的MADV_MERGEABLE区域或MADV_UNMERGEABLE区域，
当该进程将超过 ``vm.max_map_count`` 的设定，则madvise可能返回ENOMEM。（请参阅文档
Documentation/admin-guide/sysctl/vm.rst）。

与其他madvise调用一样，它们在用户地址空间的映射区域上使用：如果指定的范围包含未
映射的间隙（尽管在中间的映射区域工作），它们将报告ENOMEM，如果没有足够的内存用于
内部结构，则可能会因EAGAIN而失败。

KSM守护进程sysfs接口
====================

KSM守护进程可以由``/sys/kernel/mm/ksm/`` 中的sysfs文件控制，所有人都可以读取，但
只能由root用户写入。各接口解释如下：

pages_to_scan
        ksmd进程进入睡眠前要扫描的页数。
        例如， ``echo 100 > /sys/kernel/mm/ksm/pages_to_scan``

        默认值：100（该值被选择用于演示目的）

sleep_millisecs
        ksmd在下次扫描前应休眠多少毫秒
        例如， ``echo 20 > /sys/kernel/mm/ksm/sleep_millisecs``

        默认值：20（该值被选择用于演示目的）

merge_across_nodes
        指定是否可以合并来自不同NUMA节点的页面。当设置为0时，ksm仅合并在物理上位
        于同一NUMA节点的内存区域中的页面。这降低了访问共享页面的延迟。在有明显的
        NUMA距离上，具有更多节点的系统可能受益于设置该值为0时的更低延迟。而对于
        需要对内存使用量最小化的较小系统来说，设置该值为1（默认设置）则可能会受
        益于更大共享页面。在决定使用哪种设置之前，您可能希望比较系统在每种设置下
        的性能。 ``merge_across_nodes`` 仅当系统中没有ksm共享页面时，才能被更改设
        置：首先将接口`run` 设置为2从而对页进行去合并，然后在修改
        ``merge_across_nodes`` 后再将‘run’又设置为1，以根据新设置来重新合并。

        默认值：1（如早期的发布版本一样合并跨站点）

run
        * 设置为0可停止ksmd运行，但保留合并页面，
        * 设置为1可运行ksmd，例如， ``echo 1 > /sys/kernel/mm/ksm/run`` ，
        * 设置为2可停止ksmd运行，并且对所有目前已合并的页进行去合并，但保留可合并
          区域以供下次运行。

        默认值：0（必须设置为1才能激活KSM，除非禁用了CONFIG_SYSFS）

use_zero_pages
        指定是否应当特殊处理空页（即那些仅含zero的已分配页）。当该值设置为1时，
        空页与内核零页合并，而不是像通常情况下那样空页自身彼此合并。这可以根据
        工作负载的不同，在具有着色零页的架构上可以提高性能。启用此设置时应小心，
        因为它可能会降低某些工作负载的KSM性能，比如，当待合并的候选页面的校验和
        与空页面的校验和恰好匹配的时候。此设置可随时更改，仅对那些更改后再合并
        的页面有效。

        默认值：0（如同早期版本的KSM正常表现）

max_page_sharing
        单个KSM页面允许的最大共享站点数。这将强制执行重复数据消除限制，以避免涉
        及遍历共享KSM页面的虚拟映射的虚拟内存操作的高延迟。最小值为2，因为新创
        建的KSM页面将至少有两个共享者。该值越高，KSM合并内存的速度越快，去重
        因子也越高，但是对于任何给定的KSM页面，虚拟映射的最坏情况遍历的速度也会
        越慢。减慢了这种遍历速度就意味着在交换、压缩、NUMA平衡和页面迁移期间，
        某些虚拟内存操作将有更高的延迟，从而降低这些虚拟内存操作调用者的响应能力。
        其他任务如果不涉及执行虚拟映射遍历的VM操作，其任务调度延迟不受此参数的影
        响，因为这些遍历本身是调度友好的。

stable_node_chains_prune_millisecs
        指定KSM检查特定页面的元数据的频率（即那些达到过时信息数据去重限制标准的
        页面）单位是毫秒。较小的毫秒值将以更低的延迟来释放KSM元数据，但它们将使
        ksmd在扫描期间使用更多CPU。如果还没有一个KSM页面达到 ``max_page_sharing``
        标准，那就没有什么用。

KSM与MADV_MERGEABLE的工作有效性体现于 ``/sys/kernel/mm/ksm/`` 路径下的接口：

pages_shared
        表示多少共享页正在被使用
pages_sharing
        表示还有多少站点正在共享这些共享页，即节省了多少
pages_unshared
        表示有多少页是唯一的，但被反复检查以进行合并
pages_volatile
        表示有多少页因变化太快而无法放在tree中
full_scans
        表示所有可合并区域已扫描多少次
stable_node_chains
        达到 ``max_page_sharing`` 限制的KSM页数
stable_node_dups
        重复的KSM页数

比值 ``pages_sharing/pages_shared`` 的最大值受限制于 ``max_page_sharing``
的设定。要想增加该比值，则相应地要增加 ``max_page_sharing`` 的值。


code:
.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
.. See the bottom of this file for additional redistribution information.

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

:Original: Documentation/admin-guide/reporting-issues.rst

:译者:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

报告问题
+++++++++

简明指南（亦即 太长不看）
==========================

您面临的是否为同系列稳定版或长期支持内核的普通内核的回归？是否仍然受支持？
请搜索 `LKML内核邮件列表 <https://lore.kernel.org/lkml/>`_ 和
`Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 存档中匹配的报告并
加入讨论。如果找不到匹配的报告，请安装该系列的最新版本。如果它仍然出现问题，
请报告给稳定版邮件列表（stable@vger.kernel.org）并抄送回归邮件列表
（regressions@lists.linux.dev）；理想情况下，还可以抄送维护者和相关子系统的
邮件列表。

在所有其他情况下，请尽可能猜测是哪个内核部分导致了问题。查看MAINTAINERS文件，
了解开发人员希望如何得知问题，大多数情况下，报告问题都是通过电子邮件和抄送
相关邮件列表进行的。检查报告目的地的存档中是否已有匹配的报告；也请搜索
`LKML <https://lore.kernel.org/lkml/>`_ 和网络。如果找不到可加入的讨论，请
安装 `最新的主线内核 <https://kernel.org/>`_ 。如果仍存在问题，请发送报告。

问题已经解决了，但是您希望看到它在一个仍然支持的稳定版或长期支持系列中得到
解决？请安装其最新版本。如果它出现了问题，那么在主线中搜索修复它的更改，并
检查是否正在回传（backporting）或者已放弃；如果两者都没有，那么可询问处理
更改的人员。

**通用提醒** ：当安装和测试上述内核时，请确保它是普通的（即：没有补丁，也没
有使用附加模块）。还要确保它是在一个正常的环境中构建和运行，并且在问题发生
之前没有被污染（tainted）。

当你同时面临Linux内核的多个问题时，请分别报告。在编写报告时，要涵盖与问题
相关的所有信息，如使用的内核和发行版。如果碰见回归，请把报告抄送回归邮件列表
（regressions@lists.linux.dev）。也请试试用二分法找出源头；如果成功找到，请
在报告中写上它的提交ID并抄送sign-off-by链中的所有人。

一旦报告发出，请回答任何出现的问题，并尽可能地提供帮助。这包括通过不时重新
测试新版本并发送状态更新来推动进展。

如何向内核维护人员报告问题的逐步指南
=====================================

上面的简明指南概述了如何向Linux内核开发人员报告问题。对于已经熟悉向自由和开
源软件（FLOSS）项目报告问题的人来说，这可能是他们所需要的全部内容。对于其他
人，本部分更为详细，并一步一步地描述。为了便于阅读，它仍然尽量简洁，并省略
了许多细节；这些在逐步指南后的参考章节中进行了描述，该章节更详细地解释了每
个步骤。

注意：本节涉及的方面比简明指南多，顺序也稍有不同。这符合你的利益，以确保您
尽早意识到看起来像Linux内核毛病的问题可能实际上是由其他原因引起的。这些步骤
可以确保你最终不会觉得在这一过程中投入的时间是浪费：

 * 您是否面临硬件或软件供应商提供的Linux内核的问题？那么基本上您最好停止阅读
   本文档，转而向您的供应商报告问题，除非您愿意自己安装最新的Linux版本。寻找
   和解决问题往往需要后者。

 * 使用您喜爱的网络搜索引擎对现有报告进行粗略搜索；此外，请检查
   `Linux内核邮件列表（LKML） <https://lore.kernel.org/lkml/>`_ 的存档。如果
   找到匹配的报告，请加入讨论而不是发送新报告。

 * 看看你正在处理的问题是否为回归问题、安全问题或非常严重的问题：这些都是需
   要在接下来的一些步骤中特别处理的“高优先级问题”。

 * 确保不是内核环境导致了您面临的问题。

 * 创建一个新的备份，并将系统修复和恢复工具放在手边。

 * 确保您的系统不会通过动态构建额外的内核模块来增强其内核，像DKMS这样的解决
   方案可能在您不知情的情况下就在本地进行了这样的工作。

 * 当问题发生时，检查您的内核是否被“污染”，因为使内核设置这个标志的事件可能
   会导致您面临的问题。

 * 粗略地写下如何重现这个问题。如果您同时处理多个问题，请为每个问题单独写注
   释，并确保它们在新启动的系统上独立出现。这是必要的，因为每个问题都需要分
   别报告给内核开发人员，除非它们严重纠缠在一起。

 * 如果您正面临稳定版或长期支持版本线的回归（例如从5.10.4更新到5.10.5时出现
   故障），请查看后文“报告稳定版和长期支持内核线的回归”小节。

 * 定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式和
   位置。注意：大多数情况下不会是 bugzilla.kernel.org，因为问题通常需要通
   过邮件发送给维护人员和公共邮件列表。

 * 在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。
   如果你发现了一些相关讨论，请加入讨论而不是发送新的报告。

在完成这些准备之后，你将进入主要部分：

 * 除非您已经在运行最新的“主线”Linux内核，否则最好在报告流程前安装它。在某些
   情况下，使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案；在
   合并窗口期间，这实际上可能是最好的方法，但在开发阶段最好还是暂停几天。无论
   你选择什么版本，最好使用“普通”构建。忽略这些建议会大大增加您的报告被拒绝
   或忽略的风险。

 * 确保您刚刚安装的内核在运行时不会“污染”自己。

 * 在您刚刚安装的内核中复现这个问题。如果它没有出现，请查看下方只发生在
   稳定版和长期支持内核的问题的说明。

 * 优化你的笔记：试着找到并写出最直接的复现问题的方法。确保最终结果包含所有
   重要的细节，同时让第一次听说的人容易阅读和理解。如果您在此过程中学到了一
   些东西，请考虑再次搜索关于该问题的现有报告。

 * 如果失败涉及“panic”、“Oops”、“warning”或“BUG”，请考虑解码内核日志以查找触
   发错误的代码行。

 * 如果您的问题是回归问题，请尽可能缩小引入问题时的范围。

 * 通过详细描述问题来开始编写报告。记得包括以下条目：您为复现而安装的最新内
   核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能，将内核
   构建配置（.config）和 ``dmesg`` 的输出放在网上的某个地方，并链接到它。包
   含或上传所有其他可能相关的信息，如Oops的输出/截图或来自 ``lspci`` 的输出
   。一旦你写完了这个主要部分，请在上方插入一个正常长度的段落快速概述问题和
   影响。再在此之上添加一个简单描述问题的句子，以得到人们的阅读。现在给出一
   个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的那样发送或
   提交报告了，除非你在处理一个“高优先级问题”：它们需要按照下面“高优先级问
   题的特殊处理”所述特别关照。

 * 等待别人的反应，继续推进事情，直到你能够接受这样或那样的结果。因此，请公
   开和及时地回应任何询问。测试提出的修复。积极地测试：至少重新测试每个新主
   线版本的首个候选版本（RC），并报告你的结果。如果出现拖延，就友好地提醒一
   下。如果你没有得到任何帮助或者未能满意，请试着自己帮助自己。

报告稳定版和长期支持内核线的回归
----------------------------------

如果您发现了稳定版或长期支持内核版本线中的回归问题并按上述流程跳到这里，那么
请阅读本小节。即例如您在从5.10.4更新到5.10.5时出现了问题（从5.9.15到5.10.5则
不是）。开发人员希望尽快修复此类回归，因此有一个简化流程来报告它们：

 * 检查内核开发人员是否仍然维护你关心的Linux内核版本线：去 `kernel.org 的首页
   <https://kernel.org/>`_ ，确保此特定版本线的最新版没有“[EOL]”标记。

 * 检查 `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ 中的现有报告。

 * 从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染，并且仍然
   存在问题，因为问题可能已经在那里被修复了。如果您第一次发现供应商内核的问题，
   请检查已知最新版本的普通构建是否可以正常运行。

 * 向Linux稳定版邮件列表发送一个简短的问题报告（stable@vger.kernel.org）并抄送
   Linux回归邮件列表（regressions@lists.linux.dev）；如果你怀疑是由某子系统
   引起的，请抄送其维护人员和子系统邮件列表。大致描述问题，并解释如何复现。
   讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一步的指示。

下面的参考章节部分详细解释了这些步骤中的每一步。

报告只发生在较旧内核版本线的问题
----------------------------------

若您尝试了上述的最新主线内核，但未能在那里复现问题，那么本小节适用于您；以下
流程有助于使问题在仍然支持的稳定版或长期支持版本线，或者定期基于最新稳定版或
长期支持内核的供应商内核中得到修复。如果是这种情况，请执行以下步骤：

 * 请做好准备，接下来的几个步骤可能无法在旧版本中解决问题：修复可能太大或太
   冒险，无法移植到那里。

 * 执行前节“报告稳定版和长期支持内核线的回归”中的前三个步骤。

 * 在Linux内核版本控制系统中搜索修复主线问题的更改，因为它的提交消息可能会
   告诉你修复是否已经计划好了支持。如果你没有找到，搜索适当的邮件列表，寻找
   讨论此类问题或同行评议可能修复的帖子；然后检查讨论是否认为修复不适合支持。
   如果支持根本不被考虑，加入最新的讨论，询问是否有可能。

 * 前面的步骤之一应该会给出一个解决方案。如果仍未能成功，请向可能引起问题的
   子系统的维护人员询问建议；抄送特定子系统的邮件列表以及稳定版邮件列表

下面的参考章节部分详细解释了这些步骤中的每一步。

参考章节：向内核维护者报告问题
===============================

上面的详细指南简要地列出了所有主要步骤，这对大多数人来说应该足够了。但有时，
即使是有经验的用户也可能想知道如何实际执行这些步骤之一。这就是本节的目的，
因为它将提供关于上述每个步骤的更多细节。请将此作为参考文档：可以从头到尾
阅读它。但它主要是为了浏览和查找如何实际执行这些步骤的详细信息。

在深入挖掘细节之前，我想先给你一些一般性建议：

 * Linux内核开发人员很清楚这个过程很复杂，比其他的FLOSS项目要求更多。我们很
   希望让它更简单。但这需要在不同的地方以及一些基础设施上付诸努力，这些基础
   设施需要持续的维护；尚未有人站出来做这些工作，所以目前情况就是这样。

 * 与某些供应商签订的保证或支持合同并不能使您有权要求上游Linux内核社区的开
   发人员进行修复：这样的合同完全在Linux内核、其开发社区和本文档的范围之外。
   这就是为什么在这种情况下，你不能要求任何契约保证，即使开发人员处理的问
   题对供应商有效。如果您想主张您的权利，使用供应商的支持渠道代替。当这样做
   的时候，你可能想提出你希望看到这个问题在上游Linux内核中修复；可以这是确
   保最终修复将被纳入所有Linux发行版的唯一方法来鼓励他们。

 * 如果您从未向FLOSS项目报告过任何问题，那么您应该考虑阅读 `如何有效地报告
   缺陷 <https://www.chiark.greenend.org.uk/~sgtatham/bugs.html>`_ ， `如何
   以明智的方式提问 <http://www.catb.org/esr/faqs/smart-questions.html>`_ ，
   和 `如何提出好问题 <https://jvns.ca/blog/good-questions/>`_ 。

解决这些问题之后，可以在下面找到如何正确地向Linux内核报告问题的详细信息。

确保您使用的是上游Linux内核
----------------------------

   *您是否面临硬件或软件供应商提供的Linux内核的问题？那么基本上您最好停止阅
   读本文档，转而向您的供应商报告问题，除非您愿意自己安装最新的Linux版本。
   寻找和解决问题往往需要后者。*

与大多数程序员一样，Linux内核开发人员不喜欢花时间处理他们维护的源代码中根本
不会发生的问题的报告。这只会浪费每个人的时间，尤其是你的时间。不幸的是，当
涉及到内核时，这样的情况很容易发生，并且常常导致双方气馁。这是因为几乎所有预
装在设备（台式机、笔记本电脑、智能手机、路由器等）上的Linux内核，以及大多数
由Linux发行商提供的内核，都与由kernel.org发行的官方Linux内核相距甚远：从Linux
开发的角度来看，这些供应商提供的内核通常是古老的或者经过了大量修改，通常两点
兼具。

大多数供应商内核都不适合用来向Linux内核开发人员报告问题：您在其中遇到的问题
可能已经由Linux内核开发人员在数月或数年前修复；此外，供应商的修改和增强可能
会导致您面临的问题，即使它们看起来很小或者完全不相关。这就是为什么您应该向
供应商报告这些内核的问题。它的开发者应该查看报告，如果它是一个上游问题，直接
于上游修复或将报告转发到那里。在实践中，这有时行不通。因此，您可能需要考虑
通过自己安装最新的Linux内核内核来绕过供应商。如果如果您选择此方法，那么本指
南后面的步骤将解释如何在排除了其他可能导致您的问题的原因后执行此操作。

注意前段使用的词语是“大多数”，因为有时候开发人员实际上愿意处理供应商内核出现
的问题报告。他们是否这么做很大程度上取决于开发人员和相关问题。如果发行版只
根据最近的Linux版本对内核进行了较小修改，那么机会就比较大；例如对于Debian
GNU/Linux Sid或Fedora Rawhide所提供的主线内核。一些开发人员还将接受基于最新
稳定内核的发行版内核问题报告，只要它改动不大；例如Arch Linux、常规Fedora版本
和openSUSE Turboweed。但是请记住，您最好使用主线Linux，并避免在此流程中使用
稳定版内核，如“安装一个新的内核进行测试”一节中所详述。

当然，您可以忽略所有这些建议，并向上游Linux开发人员报告旧的或经过大量修改的
供应商内核的问题。但是注意，这样的报告经常被拒绝或忽视，所以自行小心考虑一下。
不过这还是比根本不报告问题要好：有时候这样的报告会直接或间接地帮助解决之后的
问题。

搜索现有报告（第一部分）
-------------------------

    *使用您喜爱的网络搜索引擎对现有报告进行粗略搜索；此外，请检查Linux内核
    邮件列表（LKML）的存档。如果找到匹配的报告，请加入讨论而不是发送新报告。*

报告一个别人已经提出的问题，对每个人来说都是浪费时间，尤其是作为报告人的你。
所以彻底检查是否有人已经报告了这个问题，这对你自己是有利的。在流程中的这一步，
可以只执行一个粗略的搜索：一旦您知道您的问题需要报告到哪里，稍后的步骤将告诉
您如何详细搜索。尽管如此，不要仓促完成这一步，它可以节省您的时间和减少麻烦。

只需先用你最喜欢的搜索引擎在互联网上搜索。然后再搜索Linux内核邮件列表（LKML）
存档。

如果搜索结果实在太多，可以考虑让你的搜索引擎将搜索时间范围限制在过去的一个
月或一年。而且无论你在哪里搜索，一定要用恰当的搜索关键词；也要变化几次关键
词。同时，试着从别人的角度看问题：这将帮助你想出其他的关键词。另外，一定不
要同时使用过多的关键词。记住搜索时要同时尝试包含和不包含内核驱动程序的名称
或受影响的硬件组件的名称等信息。但其确切的品牌名称（比如说“华硕红魔 Radeon
RX 5700 XT Gaming OC”）往往帮助不大，因为它太具体了。相反，尝试搜索术语，如
型号（Radeon 5700 或 Radeon 5000）和核心代号（“Navi”或“Navi10”），以及包含
和不包含其制造商（“AMD”）。

如果你发现了关于你的问题的现有报告，请加入讨论，因为你可能会提供有价值的额
外信息。这一点很重要，即使是在修复程序已经准备好或处于最后阶段，因为开发人
员可能会寻找能够提供额外信息或测试建议修复程序的人。跳到“发布报告后的责任”
一节，了解有关如何正确参与的细节。

注意，搜索 `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 网站可能
也是一个好主意，因为这可能会提供有价值的见解或找到匹配的报告。如果您发现后者，
请记住：大多数子系统都希望在不同的位置报告，如下面“你需要将问题报告到何处”
一节中所述。因此本应处理这个问题的开发人员甚至可能不知道bugzilla的工单。所以
请检查工单中的问题是否已经按照本文档所述得到报告，如果没有，请考虑这样做。

高优先级的问题？
-----------------

    *看看你正在处理的问题是否是回归问题、安全问题或非常严重的问题：这些都是
    需要在接下来的一些步骤中特别处理的“高优先级问题”。*

Linus Torvalds和主要的Linux内核开发人员希望看到一些问题尽快得到解决，因此在
报告过程中有一些“高优先级问题”的处理略有不同。有三种情况符合条件:回归、安全
问题和非常严重的问题。

如果某个应用程序或实际用例在原先的Linux内核上运行良好，但在使用类似配置编译的
较新版本上效果更差、或者根本不能用，那么你就需要处理回归问题。
Documentation/admin-guide/reporting-regressions.rst 对此进行了更详细的解释。
它还提供了很多你可能想知道的关于回归的其他信息；例如，它解释了如何将您的问题
添加到回归跟踪列表中，以确保它不会被忽略。

什么是安全问题留给您自己判断。在继续之前，请考虑阅读
Documentation/translations/zh_CN/admin-guide/security-bugs.rst ，
因为它提供了如何最恰当地处理安全问题的额外细节。

当发生了完全无法接受的糟糕事情时，此问题就是一个“非常严重的问题”。例如，
Linux内核破坏了它处理的数据或损坏了它运行的硬件。当内核突然显示错误消息
（“kernel panic”）并停止工作，或者根本没有任何停止信息时，您也在处理一个严重
的问题。注意：不要混淆“panic”（内核停止自身的致命错误）和“Oops”（可恢复错误），
因为显示后者之后内核仍然在运行。

确保环境健康
--------------

    *确保不是内核所处环境导致了你所面临的问题。*

看起来很像内核问题的问题有时是由构建或运行时环境引起的。很难完全排除这种问
题，但你应该尽量减少这种问题：

 * 构建内核时，请使用经过验证的工具，因为编译器或二进制文件中的错误可能会导
   致内核出现错误行为。

 * 确保您的计算机组件在其设计规范内运行；这对处理器、内存和主板尤为重要。因
   此，当面临潜在的内核问题时，停止低电压或超频。

 * 尽量确保不是硬件故障导致了你的问题。例如，内存损坏会导致大量的问题，这些
   问题会表现为看起来像内核问题。

 * 如果你正在处理一个文件系统问题，你可能需要用 ``fsck`` 检查一下文件系统，
   因为它可能会以某种方式被损坏，从而导致无法预期的内核行为。

 * 在处理回归问题时，要确保没有在更新内核的同时发生了其他变化。例如，这个问
   题可能是由同时更新的其他软件引起的。也有可能是在你第一次重启进入新内核时，
   某个硬件巧合地坏了。更新系统 BIOS 或改变 BIOS 设置中的某些内容也会导致
   一些看起来很像内核回归的问题。

为紧急情况做好准备
-------------------

    *创建一个全新的备份，并将系统修复和还原工具放在手边*

我得提醒您，您正在和计算机打交道，计算机有时会出现意想不到的事情，尤其是当
您折腾其操作系统的内核等关键部件时。而这就是你在这个过程中要做的事情。因此，
一定要创建一个全新的备份；还要确保你手头有修复或重装操作系统的所有工具，
以及恢复备份所需的一切。

确保你的内核不会被增强
------------------------

    *确保您的系统不会通过动态构建额外的内核模块来增强其内核，像DKMS这样的解
    决方案可能在您不知情的情况下就在本地进行了这样的工作。*

如果内核以任何方式得到增强，那么问题报告被忽略或拒绝的风险就会急剧增加。这就
是为什么您应该删除或禁用像akmods和DKMS这样的机制：这些机制会自动构建额外内核
模块，例如当您安装新的Linux内核或第一次引导它时。也要记得同时删除他们可能安装
的任何模块。然后重新启动再继续。

注意，你可能不知道你的系统正在使用这些解决方案之一：当你安装 Nvidia 专有图
形驱动程序、VirtualBox 或其他需要 Linux 内核以外的模块支持的软件时，它们通
常会静默设置。这就是为什么你可能需要卸载这些软件的软件包，以摆脱任何第三方
内核模块。

检查“污染”标志
----------------

    *当问题发生时，检查您的内核是否被“污染”，因为使内核设置这个标志的事件可
    能会导致您面临的问题。*

当某些可能会导致看起来完全不相关的后续错误的事情发生时，内核会用“污染
（taint）”标志标记自己。如果您的内核受到污染，那么您面临的可能是这样的错误。
因此在投入更多时间到这个过程中之前，尽早排除此情况可能对你有好处。这是这个
步骤出现在这里的唯一原因，因为这个过程稍后会告诉您安装最新的主线内核；然后
您将需要再次检查污染标志，因为当它出问题的时候内核报告会关注它。

在正在运行的系统上检查内核是否污染非常容易：如果 ``cat /proc/sys/kernel/tainted``
返回“0”，那么内核没有被污染，一切正常。在某些情况下无法检查该文件；这就是
为什么当内核报告内部问题（“kernel bug”）、可恢复错误（“kernel Oops”）或停止
操作前不可恢复的错误（“kernel panic”）时，它也会提到污染状态。当其中一个错
误发生时，查看打印的错误消息的顶部，搜索以“CPU:”开头的行。如果发现问题时内
核未被污染，那么它应该以“Not infected”结束；如果你看到“Tainted:”且后跟一些
空格和字母，那就被污染了。

如果你的内核被污染了，请阅读 Documentation/translations/zh_CN/admin-guide/tainted-kernels.rst
以找出原因。设法消除污染因素。通常是由以下三种因素之一引起的：

 1. 发生了一个可恢复的错误（“kernel Oops”），内核污染了自己，因为内核知道在
    此之后它可能会出现奇怪的行为错乱。在这种情况下，检查您的内核或系统日志，
    并寻找以下列文字开头的部分::

       Oops: 0000 [#1] SMP

    如方括号中的“#1”所示，这是自启动以来的第一次Oops。每个Oops和此后发生的
    任何其他问题都可能是首个Oops的后续问题，即使这两个问题看起来完全不相关。
    通过消除首个Oops的原因并在之后复现该问题，可以排除这种情况。有时仅仅
    重新启动就足够了，有时更改配置后重新启动可以消除Oops。但是在这个流程中
    不要花费太多时间在这一点上，因为引起Oops的原因可能已经在您稍后将按流程
    安装的新Linux内核版本中修复了。

 2. 您的系统使用的软件安装了自己的内核模块，例如Nvidia的专有图形驱动程序或
    VirtualBox。当内核从外部源（即使它们是开源的）加载此类模块时，它会污染
    自己：它们有时会在不相关的内核区域导致错误，从而可能导致您面临的问题。
    因此，当您想要向Linux内核开发人员报告问题时，您必须阻止这些模块加载。
    大多数情况下最简单的方法是：临时卸载这些软件，包括它们可能已经安装的任
    何模块。之后重新启动。

 3. 当内核加载驻留在Linux内核源代码staging树中的模块时，它也会污染自身。这
    是一个特殊的区域，代码（主要是驱动程序）还没有达到正常Linux内核的质量
    标准。当您报告此种模块的问题时，内核受到污染显然是没有问题的；只需确保
    问题模块是造成污染的唯一原因。如果问题发生在一个不相关的区域，重新启动
    并通过指定 ``foo.blacklist=1`` 作为内核参数临时阻止该模块被加载（用有
    问题的模块名替换“foo”）。

记录如何重现问题
------------------

    *粗略地写下如何重现这个问题。如果您同时处理多个问题，请为每个问题单独写
    注释，并确保它们在新启动的系统上独立出现。这是必要的，因为每个问题都需
    要分别报告给内核开发人员，除非它们严重纠缠在一起。*

如果你同时处理多个问题，必须分别报告每个问题，因为它们可能由不同的开发人员
处理。在一份报告中描述多种问题，也会让其他人难以将其分开。因此只有在问题严
重纠缠的情况下，才能将问题合并在一份报告中。

此外，在报告过程中，你必须测试该问题是否发生在其他内核版本上。因此，如果您
知道如何在一个新启动的系统上快速重现问题，将使您的工作更加轻松。

注意：报告只发生过一次的问题往往是没有结果的，因为它们可能是由于宇宙辐射导
致的位翻转。所以你应该尝试通过重现问题来排除这种情况，然后再继续。如果你有
足够的经验来区分由于硬件故障引起的一次性错误和难以重现的罕见内核问题，可以
忽略这个建议。

稳定版或长期支持内核的回归？
-----------------------------

    *如果您正面临稳定版或长期支持版本线的回归（例如从5.10.4更新到5.10.5时出现
    故障），请查看后文“报告稳定版和长期支持内核线的回归”小节。*

稳定版和长期支持内核版本线中的回归是Linux开发人员非常希望解决的问题，这样的
问题甚至比主线开发分支中的回归更不应出现，因为它们会很快影响到很多人。开发人员
希望尽快了解此类问题，因此有一个简化流程来报告这些问题。注意，使用更新内核版
本线的回归（比如从5.9.15切换到5.10.5时出现故障）不符合条件。

你需要将问题报告到何处
------------------------

    *定位可能引起问题的驱动程序或内核子系统。找出其开发人员期望的报告的方式
    和位置。注意：大多数情况下不会是bugzilla.kernel.org，因为问题通常需要通
    过邮件发送给维护人员和公共邮件列表。*

将报告发送给合适的人是至关重要的，因为Linux内核是一个大项目，大多数开发人员
只熟悉其中的一小部分。例如，相当多的程序员只关心一个驱动程序，比如一个WiFi
芯片驱动程序；它的开发人员可能对疏远的或不相关的“子系统”（如TCP堆栈、
PCIe/PCI子系统、内存管理或文件系统）的内部知识了解很少或完全不了解。

问题在于：Linux内核缺少一个，可以简单地将问题归档并让需要了解它的开发人员了
解它的，中心化缺陷跟踪器。这就是为什么你必须找到正确的途径来自己报告问题。
您可以在脚本的帮助下做到这一点（见下文），但它主要针对的是内核开发人员和专
家。对于其他人来说，MAINTAINERS（维护人员）文件是更好的选择。

如何阅读MAINTAINERS维护者文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

为了说明如何使用 :ref:`MAINTAINERS <maintainers>` 文件，让我们假设您的笔记
本电脑中的WiFi在更新内核后突然出现了错误行为。这种情况下可能是WiFi驱动的问
题。显然，它也可能由于驱动基于的某些代码，但除非你怀疑有这样的东西会附着在
驱动程序上。如果真的是其他的问题，驱动程序的开发人员会让合适的人参与进来。

遗憾的是，没有通用且简单的办法来检查哪个代码驱动了特定硬件组件。

在WiFi驱动出现问题的情况下，你可能想查看 ``lspci -k`` 的输出，因为它列出了
PCI/PCIe总线上的设备和驱动它的内核模块::

       [user@something ~]$ lspci -k
       [...]
       3a:00.0 Network controller: Qualcomm Atheros QCA6174 802.11ac Wireless Network Adapter (rev 32)
         Subsystem: Bigfoot Networks, Inc. Device 1535
         Kernel driver in use: ath10k_pci
         Kernel modules: ath10k_pci
       [...]

但如果你的WiFi芯片通过USB或其他内部总线连接，这种方法就行不通了。在这种情况
下，您可能需要检查您的WiFi管理器或 ``ip link`` 的输出。寻找有问题的网络接口
的名称，它可能类似于“wlp58s0”。此名称可以用来找到驱动它的模块::

       [user@something ~]$ realpath --relative-to=/sys/module//sys/class/net/wlp58s0/device/driver/module
       ath10k_pci

如果这些技巧不能进一步帮助您，请尝试在网上搜索如何缩小相关驱动程序或子系统
的范围。如果你不确定是哪一个：试着猜一下，即使你猜得不好，也会有人会帮助你
的。

一旦您知道了相应的驱动程序或子系统，您就希望在MAINTAINERS文件中搜索它。如果
是“ath10k_pci”，您不会找到任何东西，因为名称太具体了。有时你需要在网上寻找
帮助；但在此之前，请尝试使用一个稍短或修改过的名称来搜索MAINTAINERS文件，因
为这样你可能会发现类似这样的东西::

       QUALCOMM ATHEROS ATH10K WIRELESS DRIVER
       Mail:          A. Some Human <shuman@example.com>
       Mailing list:  ath10k@lists.infradead.org
       Status:        Supported
       Web-page:      https://wireless.wiki.kernel.org/en/users/Drivers/ath10k
       SCM:           git git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
       Files:         drivers/net/wireless/ath/ath10k/

注意：如果您阅读在Linux源代码树的根目录中找到的原始维护者文件，则行描述将是
缩写。例如，“Mail:（邮件）”将是“M:”，“Mailing list:（邮件列表）”将是“L”，
“Status:（状态）”将是“S:”。此文件顶部有一段解释了这些和其他缩写。

首先查看“Status”状态行。理想情况下，它应该得到“Supported（支持）”或
“Maintained（维护）”。如果状态为“Obsolete（过时的）”，那么你在使用一些过时的
方法，需要转换到新的解决方案上。有时候，只有在感到有动力时，才会有人为代码
提供“Odd Fixes”。如果碰见“Orphan”，你就完全不走运了，因为再也没有人关心代码
了，只剩下这些选项:准备好与问题共存，自己修复它，或者找一个愿意修复它的程序员。

检查状态后，寻找以“bug:”开头的一行：它将告诉你在哪里可以找到子系统特定的缺
陷跟踪器来提交你的问题。上面的例子没有此行。大多数部分都是这样，因为 Linux
内核的开发完全是由邮件驱动的。很少有子系统使用缺陷跟踪器，且其中只有一部分
依赖于 bugzilla.kernel.org。

在这种以及其他很多情况下，你必须寻找以“Mail:”开头的行。这些行提到了特定代码
的维护者的名字和电子邮件地址。也可以查找以“Mailing list:”开头的行，它告诉你
开发代码的公共邮件列表。你的报告之后需要通过邮件发到这些地址。另外，对于所有
通过电子邮件发送的问题报告，一定要抄送 Linux Kernel Mailing List（LKML）
<linux-kernel@vger.kernel.org>。在以后通过邮件发送问题报告时，不要遗漏任何
一个邮件列表!维护者都是大忙人，可能会把一些工作留给子系统特定列表上的其他开
发者；而 LKML 很重要，因为需要一个可以找到所有问题报告的地方。

借助脚本找到维护者
~~~~~~~~~~~~~~~~~~~~

对于手头有Linux源码的人来说，有第二个可以找到合适的报告地点的选择：脚本
“scripts/get_maintainer.pl”，它尝试找到所有要联系的人。它会查询MAINTAINERS
文件，并需要用相关源代码的路径来调用。对于编译成模块的驱动程序，经常可以用
这样的命令找到::

       $ modinfo ath10k_pci | grep filename | sed 's!/lib/modules/.*/kernel/!!; s!filename:!!; s!\.ko\(\|\.xz\)!!'
       drivers/net/wireless/ath/ath10k/ath10k_pci.ko

将其中的部分内容传递给脚本::

       $ ./scripts/get_maintainer.pl -f drivers/net/wireless/ath/ath10k*
       Some Human <shuman@example.com> (supporter:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
       Another S. Human <asomehuman@example.com> (maintainer:NETWORKING DRIVERS)
       ath10k@lists.infradead.org (open list:QUALCOMM ATHEROS ATH10K WIRELESS DRIVER)
       linux-wireless@vger.kernel.org (open list:NETWORKING DRIVERS (WIRELESS))
       netdev@vger.kernel.org (open list:NETWORKING DRIVERS)
       linux-kernel@vger.kernel.org (open list)

不要把你的报告发给所有的人。发送给维护者，脚本称之为“supporter:”；另外抄送
代码最相关的邮件列表，以及 Linux 内核邮件列表（LKML）。在此例中，你需要将报
告发送给 “Some Human <shuman@example.com>” ，并抄送
“ath10k@lists.infradead.org”和“linux-kernel@vger.kernel.org”。

注意：如果你用 git 克隆了 Linux 源代码，你可能需要用--git 再次调用
get_maintainer.pl。脚本会查看提交历史，以找到最近哪些人参与了相关代码的编写，
因为他们可能会提供帮助。但要小心使用这些结果，因为它很容易让你误入歧途。
例如，这种情况常常会发生在很少被修改的地方（比如老旧的或未维护的驱动程序）：
有时这样的代码会在树级清理期间被根本不关心此驱动程序的开发者修改。

搜索现有报告（第二部分）
--------------------------

    *在缺陷追踪器或问题相关邮件列表的存档中彻底搜索可能与您的问题匹配的报告。
    如果找到匹配的报告，请加入讨论而不是发送新报告。*

如前所述：报告一个别人已经提出的问题，对每个人来说都是浪费时间，尤其是作为报告
人的你。这就是为什么你应该再次搜索现有的报告。现在你已经知道问题需要报告到哪里。
如果是邮件列表，那么一般在 `lore.kernel.org <https://lore.kernel.org/>`_ 可以
找到相应存档。

但有些列表运行在其他地方。例如前面步骤中当例子的ath10k WiFi驱动程序就是这种
情况。但是你通常可以在网上很容易地找到这些列表的档案。例如搜索“archive
ath10k@lists.infradead.org”，将引导您到ath10k邮件列表的信息页，该页面顶部链接
到其 `列表存档 <https://lists.infradead.org/pipermail/ath10k/>`_ 。遗憾的是，
这个列表和其他一些列表缺乏搜索其存档的功能。在这种情况下可以使用常规的互联网
搜索引擎，并添加类似“site:lists.infadead.org/pipermail/ath10k/”这
样的搜索条件，这会把结果限制在该链接中的档案。

也请进一步搜索网络、LKML和bugzilla.kernel.org网站。如果你的报告需要发送到缺陷
跟踪器中，那么您可能还需要检查子系统的邮件列表存档，因为可能有人只在那里报告了它。

有关如何搜索以及在找到匹配报告时如何操作的详细信息，请参阅上面的“搜索现有报告
（第一部分）”。

不要急着完成报告过程的这一步：花30到60分钟甚至更多的时间可以为你和其他人节省 /
减少相当多的时间和麻烦。

安装一个新的内核进行测试
--------------------------

    *除非您已经在运行最新的“主线”Linux内核，否则最好在报告流程前安装它。在
    某些情况下，使用最新的“稳定版”Linux进行测试和报告也是可以接受的替代方案；
    在合并窗口期间，这实际上可能是最好的方法，但在开发阶段最好还是暂停几天。
    无论你选择什么版本，最好使用“普通”构建。忽略这些建议会大大增加您的报告
    被拒绝或忽略的风险。*

正如第一步的详细解释中所提到的：与大多数程序员一样，与大多数程序员一样，Linux
内核开发人员不喜欢花时间处理他们维护的源代码中根本不会发生的问题的报告。这只
会浪费每个人的时间，尤其是你的时间。这就是为什么在报告问题之前，您必须先确认
问题仍然存在于最新的上游代码中，这符合每个人的利益。您可以忽略此建议，但如前
所述：这样做会极大地增加问题报告被拒绝或被忽略的风险。

内核“最新上游”的范围通常指：

 * 安装一个主线内核；最新的稳定版内核也可以是一个选择，但大多数时候都最好避免。
   长期支持内核（有时称为“LTS内核”）不适合此流程。下一小节将更详细地解释所有
   这些。

 * 下一小节描述获取和安装这样一个内核的方法。它还指出了使用预编译内核是可以的，
   但普通的内核更好，这意味着：它是直接使用从 `kernel.org <https://kernel.org/>`_
   获得的Linux源代码构建并且没有任何方式修改或增强。

选择适合测试的版本
~~~~~~~~~~~~~~~~~~~~

前往 `kernel.org <https://kernel.org/>`_ 来决定使用哪个版本。忽略那个写着
“Latest release最新版本”的巨大黄色按钮，往下看有一个表格。在表格的顶部，你会
看到一行以“mainline”开头的字样，大多数情况下它会指向一个版本号类似“5.8-rc2”
的预发布版本。如果是这样的话，你将需要使用这个主线内核进行测试。不要让“rc”
吓到你，这些“开发版内核”实际上非常可靠——而且你已经按照上面的指示做了备份，
不是吗？

大概每九到十周，“mainline”可能会给你指出一个版本号类似“5.7”的正式版本。如果
碰见这种情况，请考虑暂停报告过程，直到下一个版本的第一个预发布（5.8-rc1）出
现在 `kernel.org <https://kernel.org/>`_ 上。这是因为 Linux 的开发周期正在
两周的“合并窗口”内。大部分的改动和所有干扰性的改动都会在这段时间内被合并到
下一个版本中。在此期间使用主线是比较危险的。内核开发者通常也很忙，可能没有
多余的时间来处理问题报告。这也是很有可能在合并窗口中应用了许多修改来修复你
所面临的问题；这就是为什么你很快就得用一个新的内核版本重新测试，就像下面“发
布报告后的责任”一节中所述的那样。

这就是为什么要等到合并窗口结束后才去做。但是如果你处理的是一些不应该等待的
东西，则无需这样做。在这种情况下，可以考虑通过 git 获取最新的主线内核（见下
文），或者使用 kernel.org 上提供的最新稳定版本。如果 mainline 因为某些原因
不无法正常工作，那么使用它也是可以接受的。总的来说：用它来重现问题也比完全
不报告问题要好。

最好避免在合并窗口外使用最新的稳定版内核，因为所有修复都必须首先应用于主线。
这就是为什么检查最新的主线内核是如此重要：你希望看到在旧版本线修复的任何问题
需要先在主线修复，然后才能得到回传，这可能需要几天或几周。另一个原因是：您
希望的修复对于回传来说可能太难或太冒险；因此再次报告问题不太可能改变任何事情。

这些方面也部分表明了为什么长期支持内核（有时称为“LTS内核”）不适合报告流程：
它们与当前代码的距离太远。因此，先去测试主线，然后再按流程走：如果主线没有
出现问题，流程将指导您如何在旧版本线中修复它。

如何获得新的 Linux 内核
~~~~~~~~~~~~~~~~~~~~~~~~~

你可以使用预编译或自编译的内核进行测试；如果你选择后者，可以使用 git 获取源
代码，或者下载其 tar 存档包。

**使用预编译的内核** ：这往往是最快速、最简单、最安全的方法——尤其是在你不熟
悉 Linux 内核的情况下。问题是：发行商或附加存储库提供的大多数版本都是从修改
过的Linux源代码构建的。因此它们不是普通的，通常不适合于测试和问题报告：这些
更改可能会导致您面临的问题或以某种方式影响问题。

但是如果您使用的是流行的Linux发行版，那么您就很幸运了：对于大部分的发行版，
您可以在网上找到包含最新主线或稳定版本Linux内核包的存储库。使用这些是完全可
以的，只要从存储库的描述中确认它们是普通的或者至少接近普通。此外，请确保软件
包包含kernel.org上提供的最新版本内核。如果这些软件包的时间超过一周，那么它们
可能就不合适了，因为新的主线和稳定版内核通常至少每周发布一次。

请注意，您以后可能需要手动构建自己的内核：有时这是调试或测试修复程序所必需的，
如后文所述。还要注意，预编译的内核可能缺少在出现panic、Oops、warning或BUG时
解码内核打印的消息所需的调试符号；如果您计划解码这些消息，最好自己编译内核
（有关详细信息，请参阅本小节结尾和“解码失败信息”小节）。

**使用git** ：熟悉 git 的开发者和有经验的 Linux 用户通常最好直接从
`kernel.org 上的官方开发仓库
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
中获取最新的 Linux 内核源代码。这些很可能比最新的主线预发布版本更新一些。不
用担心：它们和正式的预发布版本一样可靠，除非内核的开发周期目前正处于合并窗
口中。不过即便如此，它们也是相当可靠的。

**常规方法** ：不熟悉 git 的人通常最好从 `kernel.org <https://kernel.org/>`_
下载源码的tar 存档包。

如何实际构建一个内核并不在这里描述，因为许多网站已经解释了必要的步骤。如果
你是新手，可以考虑按照那些建议使用 ``make localmodconfig`` 来做，它将尝试获
取你当前内核的配置，然后根据你的系统进行一些调整。这样做并不能使编译出来的
内核更好，但可以更快地编译。

注意：如果您正在处理来自内核的pannc、Oops、warning或BUG，请在配置内核时尝试
启用 CONFIG_KALLSYMS 选项。此外，还可以启用 CONFIG_DEBUG_KERNEL 和
CONFIG_DEBUG_INFO；后者是相关选项，但只有启用前者才能开启。请注意，
CONFIG_DEBUG_INFO 会需要更多储存空间来构建内核。但这是值得的，因为这些选项将
允许您稍后精确定位触发问题的确切代码行。下面的“解码失败信息”一节对此进行了更
详细的解释。

但请记住：始终记录遇到的问题，以防难以重现。发送未解码的报告总比不报告要好。

检查“污染”标志
----------------

    *确保您刚刚安装的内核在运行时不会“污染”自己。*

正如上面已经详细介绍过的：当发生一些可能会导致一些看起来完全不相关的后续错
误的事情时，内核会设置一个“污染”标志。这就是为什么你需要检查你刚刚安装的内
核是否有设置此标志。如果有的话，几乎在任何情况下你都需要在报告问题之前先消
除它。详细的操作方法请看上面的章节。

用新内核重现问题
------------------

    *在您刚刚安装的内核中复现这个问题。如果它没有出现，请查看下方只发生在
    稳定版和长期支持内核的问题的说明。*

检查这个问题是否发生在你刚刚安装的新 Linux 内核版本上。如果新内核已经修复了，
可以考虑使用此版本线，放弃报告问题。但是请记住，只要它没有在 `kernel.org
<https://kernel.org/>`_ 的稳定版和长期版（以及由这些版本衍生出来的厂商内核）
中得到修复，其他用户可能仍然会受到它的困扰。如果你喜欢使用其中的一个，或
者只是想帮助它们的用户，请前往下面的“报告只发生在较旧内核版本线的问题”一节。

优化复现问题的描述
--------------------

    *优化你的笔记：试着找到并写出最直接的复现问题的方法。确保最终结果包含所
    有重要的细节，同时让第一次听说的人容易阅读和理解。如果您在此过程中学到
    了一些东西，请考虑再次搜索关于该问题的现有报告。*

过于复杂的报告会让别人很难理解。因此请尽量找到一个可以直接描述、易于以书面
形式理解的再现方法。包含所有重要的细节，但同时也要尽量保持简短。

在这在前面的步骤中，你很可能已经了解了一些关于你所面临的问题的点。利用这些
知识，再次搜索可以转而加入的现有报告。

解码失败信息
-------------

    *如果失败涉及“panic”、“Oops”、“warning”或“BUG”，请考虑解码内核日志以查找
    触发错误的代码行。*

当内核检测到内部问题时，它会记录一些有关已执行代码的信息。这使得在源代码中精
确定位触发问题的行并显示如何调用它成为可能。但只有在配置内核时启用了
CONFIG_DEBUG_INFO 和 CONFIG_KALLSYMS选项时，这种方法才起效。如果已启用此选项，
请考虑解码内核日志中的信息。这将使我们更容易理解是什么导致了“panic”、“Oops”、
“warning”或“BUG”，从而增加了有人提供修复的几率。

解码可以通过Linux源代码树中的脚本来完成。如果您运行的内核是之前自己编译的，
这样这样调用它::

	[user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh ./linux-5.10.5/vmlinux
	/usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/

如果您运行的是打包好的普通内核，则可能需要安装带有调试符号的相应包。然后按以下
方式调用脚本（如果发行版未打包，则可能需要从Linux源代码获取）::

	[user@something ~]$ sudo dmesg | ./linux-5.10.5/scripts/decode_stacktrace.sh \
	/usr/lib/debug/lib/modules/5.10.10-4.1.x86_64/vmlinux /usr/src/kernels/5.10.10-4.1.x86_64/

脚本将解码如下的日志行，这些日志行显示内核在发生错误时正在执行的代码的地址::

	[   68.387301] RIP: 0010:test_module_init+0x5/0xffa [test_module]

解码之后，这些行将变成这样::

	[   68.387301] RIP: 0010:test_module_init (/home/username/linux-5.10.5/test-module/test-module.c:16) test_module

在本例中，执行的代码是从文件“~/linux-5.10.5/test-module/test-module.c”构建的，
错误出现在第16行的指令中。

该脚本也会如此解码以“Call trace”开头的部分中提到的地址，该部分显示出现问题的
函数的路径。此外，脚本还会显示内核正在执行的代码部分的汇编输出。

注意，如果你没法做到这一点，只需跳过这一步，并在报告中说明原因。如果你幸运的
话，可能无需解码。如果需要的话，也许有人会帮你做这件事情。还要注意，这只是解
码内核堆栈跟踪的几种方法之一。有时需要采取不同的步骤来检索相关的详细信息。
别担心，如果您碰到的情况需要这样做，开发人员会告诉您该怎么做。

对回归的特别关照
-----------------

    *如果您的问题是回归问题，请尽可能缩小引入问题时的范围。*

Linux 首席开发者 Linus Torvalds 认为 Linux 内核永远不应恶化，这就是为什么他
认为回归是不可接受的，并希望看到它们被迅速修复。这就是为什么引入了回归的改
动导致的问题若无法通过其他方式快速解决，通常会被迅速撤销。因此，报告回归有
点像“王炸”，会迅速得到修复。但要做到这一点，需要知道导致回归的变化。通常情
况下，要由报告者来追查罪魁祸首，因为维护者往往没有时间或手头设置不便来自行
重现它。

有一个叫做“二分”的过程可以来寻找变化，这在
Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 文档中进行了详细
的描述，这个过程通常需要你构建十到二十个内核镜像，每次都尝试在构建下一个镜像
之前重现问题。是的，这需要花费一些时间，但不用担心，它比大多数人想象的要快得多。
多亏了“binary search二分搜索”，这将引导你在源代码管理系统中找到导致回归的提交。
一旦你找到它，就在网上搜索其主题、提交ID和缩短的提交ID（提交ID的前12个字符）。
如果有的话，这将引导您找到关于它的现有报告。

需要注意的是，二分法需要一点窍门，不是每个人都懂得诀窍，也需要相当多的努力，
不是每个人都愿意投入。尽管如此，还是强烈建议自己进行一次二分。如果你真的
不能或者不想走这条路，至少要找出是哪个主线内核引入的回归。比如说从 5.5.15
切换到 5.8.4 的时候出现了一些问题，那么至少可以尝试一下相近的所有的主线版本
（5.6、5.7 和 5.8）来检查它是什么时候出现的。除非你想在一个稳定版或长期支持
内核中找到一个回归，否则要避免测试那些编号有三段的版本（5.6.12、5.7.8），因
为那会使结果难以解释，可能会让你的测试变得无用。一旦你找到了引入回归的主要
版本，就可以放心地继续报告了。但请记住：在不知道罪魁祸首的情况下，开发人员
是否能够提供帮助取决于手头的问题。有时他们可能会从报告中确认是什么出现了问
题，并能修复它；有时他们可能无法提供帮助，除非你进行二分。

当处理回归问题时，请确保你所面临的问题真的是由内核引起的，而不是由其他东西
引起的，如上文所述。

在整个过程中，请记住：只有当旧内核和新内核的配置相似时，问题才算回归。这可以
通过 ``make olddefconfig`` 来实现，详细解释参见
Documentation/admin-guide/reporting-regressions.rst ；它还提供了大量其他您
可能希望了解的有关回归的信息。

撰写并发送报告
---------------

    *通过详细描述问题来开始编写报告。记得包括以下条目：您为复现而安装的最新
    内核版本、使用的Linux发行版以及关于如何复现该问题的说明。如果可能，将内
    核构建配置（.config）和 ``dmesg`` 的输出放在网上的某个地方，并链接到它。
    包含或上传所有其他可能相关的信息，如Oops的输出/截图或来自 ``lspci``
    的输出。一旦你写完了这个主要部分，请在上方插入一个正常长度的段落快速概
    述问题和影响。再在此之上添加一个简单描述问题的句子，以得到人们的阅读。
    现在给出一个更短的描述性标题或主题。然后就可以像MAINTAINERS文件告诉你的
    那样发送或提交报告了，除非你在处理一个“高优先级问题”：它们需要按照下面
    “高优先级问题的特殊处理”所述特别关照。*

现在你已经准备好了一切，是时候写你的报告了。上文前言中链接的三篇文档对如何
写报告做了部分解释。这就是为什么本文将只提到一些基本的内容以及 Linux 内核特
有的东西。

有一点是符合这两类的：你的报告中最关键的部分是标题/主题、第一句话和第一段。
开发者经常会收到许多邮件。因此，他们往往只是花几秒钟的时间浏览一下邮件，然
后再决定继续下一封或仔细查看。因此，你报告的开头越好，有人研究并帮助你的机
会就越大。这就是为什么你应该暂时忽略他们，先写出详细的报告。;-)

每份报告都应提及的事项
~~~~~~~~~~~~~~~~~~~~~~~~

详细描述你的问题是如何发生在你安装的新纯净内核上的。试着包含你之前写的和优
化过的分步说明，概述你和其他人如何重现这个问题；在极少数无法重现的情况下，
尽量描述你做了什么来触发它。

还应包括其他人为了解该问题及其环境而可能需要的所有相关信息。实际需要的东西
在很大程度上取决于具体问题，但有些事项你总是应该包括在内：

 * ``cat /proc/version`` 的输出，其中包含 Linux 内核版本号和构建时的编译器。

 * 机器正在运行的 Linux 发行版（ ``hostnamectl | grep “Operating System“`` ）

 * CPU 和操作系统的架构（ ``uname -mi`` ）

 * 如果您正在处理回归，并进行了二分，请提及导致回归的变更的主题和提交ID。

许多情况下，让读你报告的人多了解两件事也是明智之举：

 * 用于构建 Linux 内核的配置（“.config”文件）

 * 内核的信息，你从 ``dmesg`` 得到的信息写到一个文件里。确保它以像“Linux
   version 5.8-1 (foobar@example.com) (gcc (GCC) 10.2.1, GNU ld version
   2.34) #1 SMP Mon Aug 3 14:54:37 UTC 2020”这样的行开始，如果没有，那么第
   一次启动阶段的重要信息已经被丢弃了。在这种情况下，可以考虑使用
   ``journalctl -b 0 -k`` ；或者你也可以重启，重现这个问题，然后调用
   ``dmesg`` 。

这两个文件很大，所以直接把它们放到你的报告中是个坏主意。如果你是在缺陷跟踪
器中提交问题，那么将它们附加到工单中。如果你通过邮件报告问题，不要用附件附
上它们，因为那会使邮件变得太大，可以按下列之一做：

 * 将文件上传到某个公开的地方（你的网站，公共文件粘贴服务，在
   `bugzilla.kernel.org <https://bugzilla.kernel.org/>`_ 上创建的工单……），
   并在你的报告中放上链接。理想情况下请使用允许这些文件保存很多年的地方，因
   为它们可能在很多年后对别人有用；例如 5 年或 10 年后，一个开发者正在修改
   一些代码，而这些代码正是为了修复你的问题。

 * 把文件放在一边，然后说明你会在他人回复时再单独发送。只要记得报告发出去后，
   真正做到这一点就可以了。;-)

提供这些东西可能是明智的
~~~~~~~~~~~~~~~~~~~~~~~~~~

根据问题的不同，你可能需要提供更多的背景数据。这里有一些关于提供什么比较好
的建议：

 * 如果你处理的是内核的“warning”、“OOPS”或“panic”，请包含它。如果你不能复制
   粘贴它，试着用netconsole网络终端远程跟踪或者至少拍一张屏幕的照片。

 * 如果问题可能与你的电脑硬件有关，请说明你使用的是什么系统。例如，如果你的
   显卡有问题，请提及它的制造商，显卡的型号，以及使用的芯片。如果是笔记本电
   脑，请提及它的型号名称，但尽量确保意义明确。例如“戴尔 XPS 13”就不很明确，
   因为它可能是 2012 年的那款，那款除了看起来和现在销售的没有什么不同之外，
   两者没有任何共同之处。因此，在这种情况下，要加上准确的型号，例如 2019
   年内推出的 XPS 13 型号为“9380”或“7390”。像“联想 Thinkpad T590”这样的名字
   也有些含糊不清：这款笔记本有带独立显卡和不带的子型号，所以要尽量找到准确
   的型号名称或注明主要部件。

 * 说明正在使用的相关软件。如果你在加载模块时遇到了问题，你要说明正在使用的
   kmod、systemd 和 udev 的版本。如果其中一个 DRM 驱动出现问题，你要说明
   libdrm 和 Mesa 的版本；还要说明你的 Wayland 合成器或 X-Server 及其驱动。
   如果你有文件系统问题，请注明相应的文件系统实用程序的版本（e2fsprogs,
   btrfs-progs, xfsprogs……）。

 * 从内核中收集可能有用的额外信息。例如， ``lspci -nn`` 的输出可以帮助别人
   识别你使用的硬件。如果你的硬件有问题，你甚至可以给出 ``sudo lspci -vvv``
   的结果，因为它提供了组件是如何配置的信息。对于一些问题，可能最好包含
   ``/proc/cpuinfo`` ， ``/proc/ioports`` ， ``/proc/iomem`` ，
   ``/proc/modules`` 或 ``/proc/scsi/scsi`` 等文件的内容。一些子系统还提
   供了收集相关信息的工具。 ``alsa-info.sh`` `就是这样一个工具，它是音频/声
   音子系统开发者提供的  <https://www.alsa-project.org/wiki/AlsaInfo>`_ 。

这些例子应该会给你一些知识点，让你知道附上什么数据可能是明智的，但你自己也
要想一想，哪些数据对别人会有帮助。不要太担心忘记一些东西，因为开发人员会要
求提供他们需要的额外细节。但从一开始就把所有重要的东西都提供出来，会增加别
人仔细查看的机会。

重要部分：报告的开头
~~~~~~~~~~~~~~~~~~~~~~

现在你已经准备好了报告的详细部分，让我们进入最重要的部分：开头几句。现在到
报告的最前面，在你刚才写的部分之前加上类似“The detailed description:”（详细
描述）这样的内容，并在最前面插入两个新行。现在写一个正常长度的段落，大致概
述这个问题。去掉所有枯燥的细节，把重点放在读者需要知道的关键部分，以让人了
解这是怎么回事；如果你认为这个缺陷影响了很多用户，就提一下这点来吸引大家关
注。

做好这一点后，在顶部再插入两行，写一句话的摘要，快速解释报告的内容。之后你
要更加抽象，为报告写一个更短的主题/标题。

现在你已经写好了这部分，请花点时间来优化它，因为它是你的报告中最重要的部分：
很多人会先读这部分，然后才会决定是否值得花时间阅读其他部分。

现在就像 :ref:`MAINTAINERS <maintainers>` 维护者文件告诉你的那样发送或提交
报告，除非它是前面概述的那些“高优先级问题”之一：在这种情况下，请先阅读下一
小节，然后再发送报告。

高优先级问题的特殊处理
~~~~~~~~~~~~~~~~~~~~~~~~

高优先级问题的报告需要特殊处理。

**非常严重的缺陷** ：确保在主题或工单标题以及第一段中明显标出 severeness
（非常严重的）。

**回归** ：报告的主题应以“[REGRESSION]”开头。

如果您成功用二分法定位了问题，请使用引入回归之更改的标题作为主题的第二部分。
请在报告中写明“罪魁祸首”的提交ID。如果未能成功二分，请在报告中讲明最后一个
正常工作的版本（例如5.7）和最先发生问题的版本（例如5.8-rc1）。

通过邮件发送报告时，请抄送Linux回归邮件列表（regressions@lists.linux.dev）。
如果报告需要提交到某个web追踪器，请继续提交；并在提交后，通过邮件将报告转发
至回归列表；抄送相关子系统的维护人员和邮件列表。请确保报告是内联转发的，不要
把它作为附件。另外请在顶部添加一个简短的说明，在那里写上工单的网址。

在邮寄或转发报告时，如果成功二分，需要将“罪魁祸首”的作者添加到收件人中；同时
抄送signed-off-by链中的每个人，您可以在提交消息的末尾找到。

**安全问题** ：对于这种问题，你将必须评估：如果细节被公开披露，是否会对其他
用户产生短期风险。如果不会，只需按照所述继续报告问题。如果有此风险，你需要
稍微调整一下报告流程。

 * 如果 MAINTAINERS 文件指示您通过邮件报告问题，请不要抄送任何公共邮件列表。

 * 如果你应该在缺陷跟踪器中提交问题，请确保将工单标记为“私有”或“安全问题”。
   如果缺陷跟踪器没有提供保持报告私密性的方法，那就别想了，把你的报告以私人
   邮件的形式发送给维护者吧。

在这两种情况下，都一定要将报告发到 MAINTAINERS 文件中“安全联络”部分列出的
地址。理想的情况是在发送报告的时候直接抄送他们。如果您在缺陷跟踪器中提交了
报告，请将报告的文本转发到这些地址；但请在报告的顶部加上注释，表明您提交了
报告，并附上工单链接。

更多信息请参见 Documentation/translations/zh_CN/admin-guide/security-bugs.rst 。

发布报告后的责任
------------------

    *等待别人的反应，继续推进事情，直到你能够接受这样或那样的结果。因此，请
    公开和及时地回应任何询问。测试提出的修复。积极地测试：至少重新测试每个
    新主线版本的首个候选版本（RC），并报告你的结果。如果出现拖延，就友好地
    提醒一下。如果你没有得到任何帮助或者未能满意，请试着自己帮助自己。*

如果你的报告非常优秀，而且你真的很幸运，那么某个开发者可能会立即发现导致问
题的原因；然后他们可能会写一个补丁来修复、测试它，并直接发送给主线集成，同
时标记它以便以后回溯到需要它的稳定版和长期支持内核。那么你需要做的就是回复
一句“Thank you very much”（非常感谢），然后在发布后换上修复好的版本。

但这种理想状况很少发生。这就是为什么你把报告拿出来之后工作才开始。你要做的
事情要视情况而定，但通常会是下面列出的事情。但在深入研究细节之前，这里有几
件重要的事情，你需要记住这部分的过程。

关于进一步互动的一般建议
~~~~~~~~~~~~~~~~~~~~~~~~~~

**总是公开回复** ：当你在缺陷跟踪器中提交问题时，一定要在那里回复，不要私下
联系任何开发者。对于邮件报告，在回复您收到的任何邮件时，总是使用“全部回复”
功能。这包括带有任何你可能想要添加到你的报告中的额外数据的邮件：进入邮件应
用程序“已发送”文件夹，并在邮件上使用“全部回复”来回复报告。这种方法可以确保
公共邮件列表和其他所有参与者都能及时了解情况；它还能保持邮件线程的完整性，
这对于邮件列表将所有相关邮件归为一类是非常重要的。

只有两种情况不适合在缺陷跟踪器或“全部回复”中发表评论：

 * 有人让你私下发东西。

 * 你被告知要发送一些东西，但注意到其中包含需要保密的敏感信息。在这种情况下，
   可以私下发送给要求发送的开发者。但要在工单或邮件中注明你是这么做的，这
   样其他人就知道你尊重了这个要求。

**在请求解释或帮助之前先研究一下** ：在这部分过程中，有人可能会告诉你用尚未
掌握的技能做一些事情。例如你可能会被要求使用一些你从未听说过的测试工具；或
者你可能会被要求在 Linux 内核源代码上应用一个补丁来测试它是否有帮助。在某些
情况下，发个回复询问如何做就可以了。但在走这条路之前，尽量通过在互联网上搜
索自行找到答案；或者考虑在其他地方询问建议。比如询问朋友，或者到你平时常去
的聊天室或论坛发帖咨询。

**要有耐心** ：如果你真的很幸运，你可能会在几个小时内收到对你的报告的答复。
但大多数情况下会花费更多的时间，因为维护者分散在全球各地，因此可能在不同的
时区——在那里他们已经享受着远离键盘的夜晚。

一般来说，内核开发者需要一到五个工作日来回复报告。有时会花费更长的时间，因
为他们可能正忙于合并窗口、其他工作、参加开发者会议，或者只是在享受一个漫长
的暑假。

“高优先级的问题”（见上面的解释）例外：维护者应该尽快解决这些问题；这就是为
什么你应该最多等待一个星期（如果是紧急的事情，则只需两天），然后再发送友好
的提醒。

有时维护者可能没有及时回复；有时候可能会出现分歧，例如一个问题是否符合回归
的条件。在这种情况下，在邮件列表上提出你的顾虑，并请求其他人公开或私下回复
如何继续推进。如果失败了，可能应该让更高级别的维护者介入。如果是 WiFi 驱动，
那就是无线维护者；如果没有更高级别的维护者，或者其他一切努力都失败了，那
这可能是一种罕见的、可以让 Linus Torvalds 参与进来的情况。

**主动测试** ：每当一个新的主线内核版本的第一个预发布版本（rc1）发布的时候，
去检查一下这个问题是否得到了解决，或者是否有什么重要的变化。在工单中或在
回复报告的邮件中提及结果（确保所有参与讨论的人都被抄送）。这将表明你的承诺
和你愿意帮忙。如果问题持续存在，它也会提醒开发者确保他们不会忘记它。其他一
些不定期的重新测试（例如用rc3、rc5 和最终版本）也是一个好主意，但只有在相关
的东西发生变化或者你正在写什么东西的时候才报告你的结果。

这些些常规的事情就不说了，我们来谈谈报告后如何帮助解决问题的细节。

查询和测试请求
~~~~~~~~~~~~~~~

如果你的报告得到了回复则需履行以下责任：

**检查与你打交道的人** ：大多数情况下，会是维护者或特定代码区域的开发人员对
你的报告做出回应。但由于问题通常是公开报告的，所以回复的可能是任何人——包括
那些想要帮忙的人，但最后可能会用他们的问题或请求引导你完全偏离轨道。这很少
发生，但这是快速上网搜搜看你正在与谁互动是明智之举的许多原因之一。通过这样
做，你也可以知道你的报告是否被正确的人听到，因为如果讨论没有导致满意的问题
解决方案而淡出，之后可能需要提醒维护者（见下文）。

**查询数据** ：通常你会被要求测试一些东西或提供更多细节。尽快提供所要求的信
息，因为你已经得到了可能会帮助你的人的注意，你等待的时间越长就有越可能失去
关注；如果你不在数个工作日内提供信息，甚至可能出现这种结果。

**测试请求** ：当你被要求测试一个诊断补丁或可能的修复时，也要尽量及时测试。
但要做得恰当，一定不要急于求成：混淆事情很容易发生，这会给所有人带来许多困
惑。例如一个常见的错误是以为应用了一个带修复的建议补丁，但事实上并没有。即
使是有经验的测试人员也会偶尔发生这样的事情，但当有修复的内核和没有修复的内
核表现得一样时，他们大多时候会注意到。

当没有任何实质性进展时该怎么办
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

有些报告不会得到负有相关责任的 Linux 内核开发者的任何反应；或者围绕这个问题
的讨论有所发展，但渐渐淡出，没有任何实质内容产出。

在这种情况下，要等两个星期（最好是三个星期）后再发出友好的提醒：也许当你的
报告到达时，维护者刚刚离开键盘一段时间，或者有更重要的事情要处理。在写提醒
信的时候，要善意地问一下，是否还需要你这边提供什么来让事情推进下去。如果报
告是通过邮件发出来的，那就在邮件的第一行回复你的初始邮件（见上文），其中包
括下方的原始报告的完整引用：这是少数几种情况下，这样的“TOFU”（Text Over,
Fullquote Under文字在上，完整引用在下）是正确的做法，因为这样所有的收件人都
会以适当的顺序立即让细节到手头上来。

在提醒之后，再等三周的回复。如果你仍然没有得到适当的反馈，你首先应该重新考
虑你的方法。你是否可能尝试接触了错误的人？是不是报告也许令人反感或者太混乱，
以至于人们决定完全远离它？排除这些因素的最好方法是：把报告给一两个熟悉
FLOSS 问题报告的人看，询问他们的意见。同时征求他们关于如何继续推进的建议。
这可能意味着：准备一份更好的报告，让这些人在你发出去之前对它进行审查。这样
的方法完全可以；只需说明这是关于这个问题的第二份改进的报告，并附上第一份报
告的链接。

如果报告是恰当的，你可以发送第二封提醒信；在其中询问为什么报告没有得到任何
回复。第二封提醒邮件的好时机是在新 Linux 内核版本的首个预发布版本（'rc1'）
发布后不久，因为无论如何你都应该在那个时候重新测试并提供状态更新（见上文）。

如果第二次提醒的结果又在一周内没有任何反应，可以尝试联系上级维护者询问意见：
即使再忙的维护者在这时候也至少应该发过某种确认。

记住要做好失望的准备：理想状况下维护者最好对每一个问题报告做出回应，但他们
只有义务解决之前列出的“高优先级问题”。所以，如果你得到的回复是“谢谢你的报告，
我目前有更重要的问题要处理，在可预见的未来没有时间去研究这个问题”，那请不
要太沮丧。

也有可能在缺陷跟踪器或列表中进行了一些讨论之后，什么都没有发生，提醒也无助
于激励大家进行修复。这种情况可能是毁灭性的，但在 Linux 内核开发中确实会发生。
这些和其他得不到帮助的原因在本文结尾处的“为什么有些问题在被报告后没有得到
任何回应或者仍然没有修复”中进行了解释。

如果你没有得到任何帮助或问题最终没有得到解决，不要沮丧：Linux 内核是 FLOSS，
因此你仍然可以自己帮助自己。例如，你可以试着找到其他受影响的人，和他们一
起合作来解决这个问题。这样的团队可以一起准备一份新的报告，提到团队有多少人，
为什么你们认为这是应该得到解决的事情。也许你们还可以一起缩小确切原因或引
入回归的变化，这往往会使修复更容易。而且如果运气好的话，团队中可能会有懂点
编程的人，也许能写出一个修复方案。

“报告稳定版和长期支持内核线的回归”的参考
------------------------------------------

本小节提供了在稳定版和长期支持内核线中面对回归时需要执行的步骤的详细信息。

确保特定版本线仍然受支持
~~~~~~~~~~~~~~~~~~~~~~~~~

    *检查内核开发人员是否仍然维护你关心的Linux内核版本线：去 kernel.org 的
    首页，确保此特定版本线的最新版没有“[EOL]”标记。*

大多数内核版本线只支持三个月左右，因为延长维护时间会带来相当多的工作。因此，
每年只会选择一个版本来支持至少两年（通常是六年）。这就是为什么你需要检查
内核开发者是否还支持你关心的版本线。

注意，如果 `kernel.org <https://kernel.org/>`_ 在首页上列出了两个“稳定”版本，
你应该考虑切换到较新的版本，而忘掉较旧的版本：对它的支持可能很快就会结束。
然后，它将被标记为“生命周期结束”（EOL）。达到这个程度的版本线仍然会在
`kernel.org <https://kernel.org/>`_ 首页上被显示一两周，但不适合用于测试和
报告。

搜索稳定版邮件列表
~~~~~~~~~~~~~~~~~~~

    *检查Linux稳定版邮件列表中的现有报告。*

也许你所面临的问题已经被发现，并且已经或即将被修复。因此，请在 `Linux 稳定
版邮件列表的档案 <https://lore.kernel.org/stable/>`_ 中搜索类似问题的报告。
如果你找到任何匹配的问题，可以考虑加入讨论，除非修复工作已经完成并计划很快
得到应用。

用最新版本复现问题
~~~~~~~~~~~~~~~~~~~

    *从特定的版本线安装最新版本作为纯净内核。确保这个内核没有被污染，并且仍
    然存在问题，因为问题可能已经在那里被修复了。*

在投入更多时间到这个过程中之前，你要检查这个问题是否在你关注的版本线的最新
版本中已经得到了修复。这个内核需要是纯净的，在问题发生之前不应该被污染，正
如上面已经在测试主线的过程中详细介绍过的一样。

您是否是第一次注意到供应商内核的回归？供应商的更改可能会发生变化。你需要重新
检查排除来这个问题。当您从5.10.4-vendor.42更新到5.10.5-vendor.43时，记录损坏
的信息。然后在测试了前一段中所述的最新5.10版本之后，检查Linux 5.10.4的普通版本
是否也可以正常工作。如果问题在那里出现，那就不符合上游回归的条件，您需要切换
回主逐步指南来报告问题。

报告回归
~~~~~~~~~~

    *向Linux稳定版邮件列表发送一个简短的问题报告(stable@vger.kernel.org)并
    抄送Linux回归邮件列表（regressions@lists.linux.dev）；如果你怀疑是由某
    子系统引起的，请抄送其维护人员和子系统邮件列表。大致描述问题，并解释如
    何复现。讲清楚首个出现问题的版本和最后一个工作正常的版本。然后等待进一
    步的指示。*

当报告在稳定版或长期支持内核线内发生的回归（例如在从5.10.4更新到5.10.5时），
一份简短的报告足以快速报告问题。因此只需向稳定版和回归邮件列表发送粗略的描述；
不过如果你怀疑某子系统导致此问题的话，请一并抄送其维护人员和子系统邮件列表，
这会加快进程。

请注意，如果您能够指明引入问题的确切版本，这将对开发人员有很大帮助。因此
如果有时间的话，请尝试使用普通内核找到该版本。让我们假设发行版发布Linux内核
5.10.5到5.10.8的更新时发生了故障。那么按照上面的指示，去检查该版本线中的最新
内核，比如5.10.9。如果问题出现，请尝试普通5.10.5，以确保供应商应用的补丁不会
干扰。如果问题没有出现，那么尝试5.10.7，然后直到5.10.8或5.10.6（取决于结果）
找到第一个引入问题的版本。在报告中写明这一点，并指出5.10.9仍然存在故障。

前一段基本粗略地概述了“二分”方法。一旦报告出来，您可能会被要求做一个正确的
报告，因为它允许精确地定位导致问题的确切更改（然后很容易被恢复以快速修复问题）。
因此如果时间允许，考虑立即进行适当的二分。有关如何详细信息，请参阅“对回归的
特别关照”部分和文档 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst 。
如果成功二分的话，请将“罪魁祸首”的作者添加到收件人中；同时抄送所有在
signed-off-by链中的人，您可以在提交消息的末尾找到。

“报告仅在旧内核版本线中发生的问题”的参考
----------------------------------------

本节详细介绍了如果无法用主线内核重现问题，但希望在旧版本线（又称稳定版内核和
长期支持内核）中修复问题时需要采取的步骤。

有些修复太复杂
~~~~~~~~~~~~~~~

    *请做好准备，接下来的几个步骤可能无法在旧版本中解决问题：修复可能太大或
    太冒险，无法移植到那里。*

即使是微小的、看似明显的代码变化，有时也会带来新的、完全意想不到的问题。稳
定版和长期支持内核的维护者非常清楚这一点，因此他们只对这些内核进行符合
Documentation/translations/zh_CN/process/stable-kernel-rules.rst 中所列出的
规则的修改。

复杂或有风险的修改不符合条件，因此只能应用于主线。其他的修复很容易被回溯到
最新的稳定版和长期支持内核，但是风险太大，无法集成到旧版内核中。所以要注意
你所希望的修复可能是那些不会被回溯到你所关心的版本线的修复之一。在这种情况
下，你将别无选择，要么忍受这个问题，要么切换到一个较新的 Linux 版本，除非你
想自己把修复补丁应用到你的内核中。

通用准备
~~~~~~~~~~

    *执行上面“报告仅在旧内核版本线中发生的问题”一节中的前三个步骤。*

您需要执行本指南另一节中已经描述的几个步骤。这些步骤将让您：

 * 检查内核开发人员是否仍然维护您关心的Linux内核版本行。

 * 在Linux稳定邮件列表中搜索退出的报告。

 * 检查最新版本。

检查代码历史和搜索现有的讨论
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    *在Linux内核版本控制系统中搜索修复主线问题的更改，因为它的提交消息可能
    会告诉你修复是否已经计划好了支持。如果你没有找到，搜索适当的邮件列表，
    寻找讨论此类问题或同行评议可能修复的帖子；然后检查讨论是否认为修复不适
    合支持。如果支持根本不被考虑，加入最新的讨论，询问是否有可能。*

在许多情况下，你所处理的问题会发生在主线上，但已在主线上得到了解决。修正它
的提交也需要被回溯才能解决这个问题。这就是为什么你要搜索它或任何相关讨论。

 * 首先尝试在存放 Linux 内核源代码的 Git 仓库中找到修复。你可以通过
   `kernel.org 上的网页
   <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/>`_
   或 `GitHub 上的镜像 <https://github.com/torvalds/linux>`_ 来实现；如果你
   有一个本地克隆，你也可以在命令行用 ``git log --grep=<pattern>`` 来搜索。

   如果你找到了修复，请查看提交消息的尾部是否包含了类似这样的“稳定版标签”：

          Cc: <stable@vger.kernel.org> # 5.4+

   像上面这行，开发者标记了安全修复可以回传到 5.4 及以后的版本。大多数情况
   下，它会在两周内被应用到那里，但有时需要更长的时间。

 * 如果提交没有告诉你任何东西，或者你找不到修复，请再找找关于这个问题的讨论。
   用你最喜欢的搜索引擎搜索网络，以及 `Linux kernel developers mailing
   list 内核开发者邮件列表 <https://lore.kernel.org/lkml/>`_ 的档案。也可以
   阅读上面的 `定位导致问题的内核区域` 一节，然后按照说明找到导致问题的子系
   统：它的缺陷跟踪器或邮件列表存档中可能有你要找的答案。

 * 如果你看到了一个计划的修复，请按上所述在版本控制系统中搜索它，因为提交可
   能会告诉你是否可以进行回溯。

   * 检查讨论中是否有任何迹象表明，该修复程序可能风险太大，无法回溯到你关心
     的版本线。如果是这样的话，你必须忍受这个问题，或者切换到应用了修复的内
     核版本线。

   * 如果修复的问题未包含稳定版标签，并且没有讨论过回溯问题，请加入讨论：如
     果合适的话，请提及你所面对的问题的版本，以及你希望看到它被修复。

请求建议
~~~~~~~~~

    *前面的步骤之一应该会给出一个解决方案。如果仍未能成功，请向可能引起问题
    的子系统的维护人员询问建议；抄送特定子系统的邮件列表以及稳定版邮件列表。*

如果前面的三个步骤都没有让你更接近解决方案，那么只剩下一个选择：请求建议。
在你发给可能是问题根源的子系统的维护者的邮件中这样做；抄送子系统的邮件列表
以及稳定版邮件列表（stable@vger.kernel.org）。

为什么有些问题在报告后没有任何回应或仍未解决？
===============================================

当向 Linux 开发者报告问题时，要注意只有“高优先级的问题”（回归、安全问题、严
重问题）才一定会得到解决。如果维护者或其他人都失败了，Linus Torvalds 他自己
会确保这一点。他们和其他内核开发者也会解决很多其他问题。但是要知道，有时他
们也会不能或不愿帮忙；有时甚至没有人发报告给他们。

最好的解释就是那些内核开发者常常是在业余时间为 Linux 内核做出贡献。内核中的
不少驱动程序都是由这样的程序员编写的，往往只是因为他们想让自己的硬件可以在
自己喜欢的操作系统上使用。

这些程序员大多数时候会很乐意修复别人报告的问题。但是没有人可以强迫他们这样
做，因为他们是自愿贡献的。

还有一些情况下，这些开发者真的很想解决一个问题，但却不能解决：有时他们缺乏
硬件编程文档来解决问题。这种情况往往由于公开的文档太简陋，或者驱动程序是通
过逆向工程编写的。

业余开发者迟早也会不再关心某驱动。也许他们的测试硬件坏了，被更高级的玩意取
代了，或者是太老了以至于只能在计算机博物馆里找到。有时开发者根本就不关心他
们的代码和 Linux 了，因为在他们的生活中一些不同的东西变得更重要了。在某些情
况下，没有人愿意接手维护者的工作——也没有人可以被强迫，因为对 Linux 内核的贡
献是自愿的。然而被遗弃的驱动程序仍然存在于内核中：它们对人们仍然有用，删除
它们可能导致回归。

对于那些为 Linux 内核工作而获得报酬的开发者来说，情况并没有什么不同。这些人
现在贡献了大部分的变更。但是他们的雇主迟早也会停止关注他们的代码或者让程序
员专注于其他事情。例如，硬件厂商主要通过销售新硬件来赚钱；因此，他们中的不
少人并没有投入太多时间和精力来维护他们多年前就停止销售的东西的 Linux 内核驱
动。企业级 Linux 发行商往往持续维护的时间比较长，但在新版本中往往会把对老旧
和稀有硬件的支持放在一边，以限制范围。一旦公司抛弃了一些代码，往往由业余贡
献者接手，但正如上面提到的：他们迟早也会放下代码。

优先级是一些问题没有被修复的另一个原因，因为维护者相当多的时候是被迫设置这
些优先级的，因为在 Linux 上工作的时间是有限的。对于业余时间或者雇主给予他们
的开发人员用于上游内核维护工作的时间也是如此。有时维护人员也会被报告淹没，
即使一个驱动程序几乎完美地工作。为了不被完全缠住，程序员可能别无选择，只能
对问题报告进行优先级排序而拒绝其中的一些报告。

不过这些都不用太过担心，很多驱动都有积极的维护者，他们对尽可能多的解决问题
相当感兴趣。

结束语
=======

与其他免费/自由&开源软件（Free/Libre & Open Source Software，FLOSS）相比，
向 Linux 内核开发者报告问题是很难的：这个文档的长度和复杂性以及字里行间的内
涵都说明了这一点。但目前就是这样了。这篇文字的主要作者希望通过记录现状来为
以后改善这种状况打下一些基础。

..
   end-of-content
..
   This English version of this document is maintained by Thorsten Leemhuis
   <linux@leemhuis.info>. If you spot a typo or small mistake, feel free to
   let him know directly and he'll fix it. For translation problems, please
   contact with translators. You are free to do the same in a mostly informal
   way if you want to contribute changes to the text, but for copyright
   reasons please CC linux-doc@vger.kernel.org and "sign-off" your
   contribution as Documentation/process/submitting-patches.rst outlines in
   the section "Sign your work - the Developer's Certificate of Origin".
..
   This text is available under GPL-2.0+ or CC-BY-4.0, as stated at the top
   of the file. If you want to distribute this text under CC-BY-4.0 only,
   please use "The Linux kernel developers" for author attribution and link
   this as source:
   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/admin-guide/reporting-issues.rst
..
   Note: Only the content of this RST file as found in the Linux kernel sources
   is available under CC-BY-4.0, as versions of this text that were processed
   (for example by the kernel's build system) might contain content taken from
   files which use a more restrictive license.


code:
.. SPDX-License-Identifier: (GPL-2.0+ OR CC-BY-4.0)
.. 【重分发信息参见本文件结尾】

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

:Original: Documentation/admin-guide/reporting-regressions.rst

:译者:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

============
报告回归问题
============

“*我们拒绝出现回归*”是Linux内核开发的首要规则；Linux的发起者和领军开发者Linus
Torvalds立下了此规则并确保它被落实。

本文档描述了这条规则对用户的意义，以及Linux内核开发模型如何确保解决所有被报告
的回归；关于内核开发者如何处理的方面参见 Documentation/process/handling-regressions.rst 。

本文重点（亦即“太长不看”）
==========================

#. 如果某程序在原先的Linux内核上运行良好，但在较新版本上效果更差、或者根本不
   能用，那么你就碰见回归问题了。注意，新内核需要使用类似配置编译；更多相关细
   节参见下方。

#. 按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
   所说的报告你的问题，该文档已经包含了所有关于回归的重要方面，为了方便起见也
   复制到了下面。两个重点：在报告主题中使用“[REGRESSION]”开头并抄送或转发到
   `回归邮件列表 <https://lore.kernel.org/regressions/>`_
   （regressions@lists.linux.dev）。

#. 可选但是建议：在发送或转发报告时，指明该回归发生的起点，以便Linux内核回归
   追踪机器人“regzbot”可以追踪此问题::

       #regzbot introduced v5.13..v5.14-rc1

与用户相关的所有Linux内核回归细节
=================================

基本重点
--------

什么是“回归”以及什么是“无回归规则”？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

如果某程序/实例在原先的Linux内核上运行良好，但在较新版本上效果更差、或者根本
不能用，那么你就碰见回归问题了。“无回归规则”不允许出现这种情况。如果偶然发
生了，导致问题的开发者应当迅速修复问题。

也就是说，若Linux 5.13中的WiFi驱动程序运行良好，但是在5.14版本上却不能用、速
度明显变慢或出现错误，那就出现了回归。如果某正常工作的应用程序突然在新内核上
出现不稳定，这也是回归；这些问题可能是由于procfs、sysfs或Linux提供给用户空间
软件的许多其他接口之一的变化。但请记住，前述例子中的5.14需要使用类似于5.13的
配置构建。这可以用 ``make olddefconfig`` 实现，详细解释见下。

注意本节第一句话中的“实例”：即使开发者需要遵循“无回归”规则，但仍可自由地改
变内核的任何方面，甚至是导出到用户空间的API或ABI，只要别破坏现有的应用程序或
用例。

还需注意，“无回归”规则只限制内核提供给用户空间的接口。它不适用于内核内部接
口，比如一些外部开发的驱动程序用来插入钩子到内核的模块API。

如何报告回归？
~~~~~~~~~~~~~~

只需按照 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 中
所说的报告你的问题，该文档已经包含了要点。下面几点概述了一下只在回归中重要的
方面：

 * 在检查可加入讨论的现有报告时，别忘了搜索 `Linux回归邮件列表
   <https://lore.kernel.org/regressions/>`_ 和 `regzbot网页界面
   <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。

 * 在报告主题的开头加上“[REGRESSION]”。

 * 在你的报告中明确最后一个正常工作的内核版本和首个出问题的版本。如若可能，
   用二分法尝试找出导致回归的变更，更多细节见下。

 * 记得把报告发到Linux回归邮件列表（regressions@lists.linux.dev）。

   * 如果通过邮件报告回归，请抄送回归列表。

   * 如果你使用某些缺陷追踪器报告回归，请通过邮件转发已提交的报告到回归列表，
     并抄送维护者以及出问题的相关子系统的邮件列表。

   如果是稳定版或长期支持版系列（如v5.15.3…v5.15.5）的回归，请记得抄送
   `Linux稳定版邮件列表 <https://lore.kernel.org/stable/>`_ （stable@vger.kernel.org）。

  如果你成功地执行了二分，请抄送肇事提交的信息中所有签了“Signed-off-by:”的人。

在抄送你的报告到列表时，也请记得通知前述的Linux内核回归追踪机器人。只需在邮件
中包含如下片段::

       #regzbot introduced: v5.13..v5.14-rc1

Regzbot会就将你的邮件视为在某个特定版本区间的回归报告。上例中即linux v5.13仍
然正常，而Linux 5.14-rc1是首个您遇到问题的版本。如果你执行了二分以查找导致回
归的提交，请使用指定肇事提交的id代替::

       #regzbot introduced: 1f2e3d4c5d

添加这样的“regzbot命令”对你是有好处的，它会确保报告不会被忽略。如果你省略了
它，Linux内核的回归跟踪者会把你的回归告诉regzbot，只要你发送了一个副本到回归
邮件列表。但是回归跟踪者只有一个人，有时不得不休息或甚至偶尔享受可以远离电脑
的时光（听起来很疯狂）。因此，依赖此人手动将回归添加到 `已追踪且尚未解决的
Linux内核回归列表 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 和
regzbot发送的每周回归报告，可能会出现延迟。 这样的延误会导致Linus Torvalds
在决定“继续开发还是发布新版本？”时忽略严重的回归。

真的修复了所有的回归吗？
~~~~~~~~~~~~~~~~~~~~~~~~

几乎所有都是，只要引起问题的变更（肇事提交）被可靠定位。也有些回归可以不用这
样，但通常是必须的。

谁需要找出回归的根本原因？
~~~~~~~~~~~~~~~~~~~~~~~~~~

受影响代码区域的开发者应该自行尝试定位问题所在。但仅靠他们的努力往往是不可
能做到的，很多问题只发生在开发者的无法接触的其他特定外部环境中——例如特定的
硬件平台、固件、Linux发行版、系统的配置或应用程序。这就是为什么最终往往是报
告者定位肇事提交；有时用户甚至需要再运行额外测试以查明确切的根本原因。开发
者应该提供建议和可能的帮助，以使普通用户更容易完成该流程。

如何找到罪魁祸首？
~~~~~~~~~~~~~~~~~~

如 Documentation/translations/zh_CN/admin-guide/reporting-issues.rst （简要）
和 Documentation/translations/zh_CN/admin-guide/bug-bisect.rst （详细）中所
述，执行二分。听起来工作量很大，但大部分情况下很快就能找到罪魁祸首。如果这很
困难或可靠地重现问题很耗时，请考虑与其他受影响的用户合作，一起缩小搜索范围。

当出现回归时我可以向谁寻求建议？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

发送邮件到回归邮件列表（regressions@lists.linux.dev）同时抄送Linux内核的回归
跟踪者（regressions@leemhuis.info）;如果问题需要保密处理，可以省略列表。

关于回归的更多细节
------------------

“无回归规则”的目标是什么？
~~~~~~~~~~~~~~~~~~~~~~~~~~

用户应该放心升级内核版本，而不必担心有程序可能崩溃。这符合内核开发者的利益，
可以使更新有吸引力：他们不希望用户停留在停止维护或超过一年半的稳定/长期Linux
版本系列上。这也符合所有人的利益，因为 `那些系列可能含有已知的缺陷、安全问题
或其他后续版本已经修复的问题
<http://www.kroah.com/log/blog/2018/08/24/what-stable-kernel-should-i-use/>`_ 。
此外，内核开发者希望使用户测试最新的预发行版或常规发行版变得简单而有吸引力。
这同样符合所有人的利益，如果新版本出来后很快就有相关报告，会使追踪和修复问题
更容易。

实际中“无回归”规则真的可行吗？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这不是句玩笑话，请见Linux创建者和主要开发人员Linus Torvalds在邮件列表中的许
多发言，其中一些在 Documentation/process/handling-regressions.rst 中被引用。

此规则的例外情况极为罕见；之前当开发者认为某个特定的情况有必要援引例外时，
基本都被证明错了。

谁来确保“无回归”被落实？
~~~~~~~~~~~~~~~~~~~~~~~~

照看和支撑树的子系统维护者应该关心这一点——例如，Linus Torvalds之于主线，
Greg Kroah-Hartman等人之于各种稳定/长期系列。

他们都得到了别人的帮助，以确保回归报告不会被遗漏。其中之一是Thorsten
Leemhuis，他目前担任Linux内核的“回归跟踪者”；为了做好这项工作，他使用了
regzbot——Linux内核回归跟踪机器人。所以这就是为什么要抄送或转发你的报告到
回归邮件列表来通知这些人，已经最好在你的邮件中包含“regzbot命令”来立即追踪它。

回归通常多久能修复？
~~~~~~~~~~~~~~~~~~~~

开发者应该尽快修复任何被报告的回归，以提供及时为受影响的用户提供解决方案，并
防止更多用户遇到问题；然而，开发人员需要花足够的时间和注意力确保回归修复不会
造成额外的损害。

因此，答案取决于各种因素，如回归的影响、存在时长或出现于哪个Linux版本系列。
但最终，大多数的回归应该在两周内修复。

当问题可以通过升级某些软件解决时，是回归吗？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

基本都是。如果开发人员告诉您其他情况，请咨询上述回归跟踪者。

当新内核变慢或能耗增加，是回归吗？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

是的，但有一些差别。在微型基准测试中变慢5%不太可能被视为回归，除非它也会对
广泛基准测试的结果产生超过1%的影响。如果有疑问，请寻求建议。

当更新Linux时外部内核模块崩溃了，是回归吗？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

不，因为“无回归”规则仅限于Linux内核提供给用户空间的接口和服务。因此，它不包括
构建或运行外部开发的内核模块，因为它们在内核空间中运行与挂进内核使用的内部接
口偶尔会变化。

如何处理安全修复引起的回归？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在极为罕见的情况下，安全问题无法在不引起回归的情况下修复；这些修复都被放弃了，
因为它们终究会引起问题。幸运的是这种两难境地基本都可以避免，受影响区域的主要
开发者以及Linus Torvalds本人通常都会努力在不引入回归的情况下解决安全问题。

如果你仍然面临此种情况，请查看邮件列表档案是否有人尽力避免过回归。如果没有，
请报告它；如有疑问，请如上所述寻求建议。

当修复回归时不可避免会引入另一个，如何处理？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

很遗憾这种事确实会出现，但幸运的是并不经常出现；如果发生了，受影响代码区的资
深开发者应当调查该问题以找到避免回归的解决方法，至少避免它们的影响。如果你遇
到这样的情况，如上所述：检查之前的讨论是否有人已经尽了最大努力，如有疑问请寻
求建议。

小提示：如果人们在每个开发周期中定期给出主线预发布（即v5.15-rc1或-rc3）以供
测试，则可以避免这种情况。为了更好地解释，可以设想一个在Linux v5.14和v5.15-rc1
之间集成的更改，该更改导致了回归，但同时是应用于5.15-rc1的其他改进的强依赖。
如果有人在5.15发布之前就发现并报告了这个问题，那么所有更改都可以直接撤销，从
而解决回归问题。而就在几天或几周后，此解决方案变成了不可能，因为一些软件可能
已经开始依赖于后续更改之一：撤销所有更改将导致上述用户软件出现回归，这是不可
接受的。

若我所依赖的功能在数月前被移除了，是回归吗？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

是的，但如前节所述，通常很难修复此类回归。因此需要逐案处理。这也是定期测试主
线预发布对所有人有好处的另一个原因。

如果我似乎是唯一受影响的人，是否仍适用“无回归”规则？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

适用，但仅限于实际使用：Linux开发人员希望能够自由地取消那些只能在阁楼和博物
馆中找到的硬件的支持。

请注意，有时为了取得进展，不得不出现回归——后者也是防止Linux停滞不前所必需
的。因此如果回归所影响的用户很少，那么为了他们和其他人更大的利益，还是让事情
过去吧。尤其是存在某种规避回归的简单方法，例如更新一些软件或者使用专门为此目
的创建的内核参数。

回归规则是否也适用于staging树中的代码？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

不，参见 `适用于所有staging代码配置选项的帮助文本
<https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/staging/Kconfig>`_ ，
其早已声明::

       请注意：这些驱动正在积极开发中，可能无法正常工作，并可能包含会在不久的
       将来发生变化的用户接口。

虽然staging开发人员通常坚持“无回归”的原则，但有时为了取得进展也会违背它。这就
是为什么当staging树的WiFi驱动被基本推倒重来时，有些用户不得不处理回归（通常可
以忽略）。

为什么较新版本必须“使用相似配置编译”？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

因为Linux内核开发人员有时会集成已知的会导致回归的变更，但使它们成为可选的，并
在内核的默认配置下禁用它们。这一技巧允许进步，否则“无回归”规则将导致停滞。

例如，试想一个新的可以阻止恶意软件滥用某个内核的接口的安全特性，同时又需要满足
另一个很罕见的应用程序。上述的方法可使两方都满意：使用这些应用程序的人可以关闭
新的安全功能，而其他不会遇到麻烦的人可以启用它。

如何创建与旧内核相似的配置？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

用一个已知良好的内核启动机器，并用 ``make olddefconfig`` 配置新版的Linux。这
会让内核的构建脚本从正在运行的内核中摘录配置文件（“.config”文件），作为即将编
译的新版本的基础配置；同时将所有新的配置选项设为默认值，以禁用可能导致回归的
新功能。

如何报告在预编译的普通内核中发现的回归？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

您需要确保新的内核是用与旧版相似的配置编译（见上文），因为那些构建它们的人可
能启用了一些已知的与新内核不兼容的特性。如有疑问，请向内核的提供者报告问题并
寻求建议。

用“regzbot”追踪回归的更多信息
-----------------------------

什么是回归追踪？为啥我需要关心它？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

像“无回归”这样的规则需要有人来确保它们被遵守，否则会被有意/无意打破。历史证
明了这一点对于Linux内核开发也适用。这就是为什么Linux内核的回归跟踪者Thorsten
Leemhuis，，和另一些人尽力关注所有的回归直到他们解决。他们从未为此获得报酬，
因此这项工作是在尽最大努力的基础上完成的。

为什么/如何使用机器人追踪Linux内核回归？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

由于Linux内核开发过程的分布式和松散结构，完全手动跟踪回归已经被证明是相当困难
的。因此Linux内核的回归跟踪者开发了regzbot来促进这项工作，其长期目标是尽可能为
所有相关人员自动化回归跟踪。

Regzbot通过监视跟踪的回归报告的回复来工作。此外，它还查找用“Link:”标签引用这
些报告的补丁；对这些补丁的回复也会被跟踪。结合这些数据，可以很好地了解当前修
复过程的状态。

如何查看regzbot当前追踪的回归？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

参见 `regzbot在线 <https://linux-regtracking.leemhuis.info/regzbot/>`_ 。

何种问题可以由regzbot追踪？
~~~~~~~~~~~~~~~~~~~~~~~~~~~

该机器人只为了跟踪回归，因此请不要让regzbot涉及常规问题。但是对于Linux内核的
回归跟踪者来说，让regzbot跟踪严重问题也可以，如有关挂起、损坏数据或内部错误
（Panic、Oops、BUG（）、warning…）的报告。

如何修改被追踪回归的相关信息？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在直接或间接回复报告邮件时使用“regzbot命令”即可。最简单的方法是：在“已发送”文
件夹或邮件列表存档中找到报告，然后使用邮件客户端的“全部回复”功能对其进行回复。
在该邮件中的独立段落中可使用以下命令之一（即使用空行将这些命令中的一个或多个与
其余邮件文本分隔开）。

 * 更新回归引入起点，例如在执行二分之后::

       #regzbot introduced: 1f2e3d4c5d

 * 设置或更新标题::

       #regzbot title: foo

 * 监视讨论或bugzilla.kernel.org上有关讨论或修复的工单::

       #regzbot monitor: https://lore.kernel.org/r/30th.anniversary.repost@klaava.Helsinki.FI/
       #regzbot monitor: https://bugzilla.kernel.org/show_bug.cgi?id=123456789

 * 标记一个有更多相关细节的地方，例如有关但主题不同的邮件列表帖子或缺陷追踪器中的工单::

       #regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=123456789

 * 标记回归已失效::

       #regzbot invalid: wasn't a regression, problem has always existed

Regzbot还支持其他一些主要由开发人员或回归追踪人员使用的命令。命令的更多细节请
参考 `入门指南 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/getting_started.md>`_
和 `参考手册 <https://gitlab.com/knurd42/regzbot/-/blob/main/docs/reference.md>`_ 。

..
   正文结束
..
   如本文件开头所述，本文以GPL-2.0+或CC-BY-4.0许可发行。如您想仅在CC-BY-4.0许
   可下重分发本文，请用“Linux内核开发者”作为作者，并用如下链接作为来源：
   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/translations/zh_CN/admin-guide/reporting-regressions.rst
..
   注意：本RST文件内容只有在来自Linux内核源代码时是使用CC-BY-4.0许可的，因为经
   过处理的版本（如经内核的构建系统）可能包含来自使用更严格许可证的文件的内容。


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

:Original: :doc:`../../../admin-guide/security-bugs`

:译者:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

安全缺陷
=========

Linux内核开发人员非常重视安全性。因此我们想知道何时发现了安全漏洞，以便尽快
修复和披露。请向Linux内核安全团队报告安全漏洞。

联络
-----

可以通过电子邮件<security@kernel.org>联系Linux内核安全团队。这是一个安全人员
的私有列表，他们将帮助验证错误报告并开发和发布修复程序。如果您已经有了一个
修复，请将其包含在您的报告中，这样可以大大加快进程。安全团队可能会从区域维护
人员那里获得额外的帮助，以理解和修复安全漏洞。

与任何缺陷一样，提供的信息越多，诊断和修复就越容易。如果您不清楚哪些信息有用，
请查看“Documentation/translations/zh_CN/admin-guide/reporting-issues.rst”中
概述的步骤。任何利用漏洞的攻击代码都非常有用，未经报告者同意不会对外发布，除
非已经公开。

请尽可能发送无附件的纯文本电子邮件。如果所有的细节都藏在附件里，那么就很难对
一个复杂的问题进行上下文引用的讨论。把它想象成一个
:doc:`常规的补丁提交 <../process/submitting-patches>` （即使你还没有补丁）：
描述问题和影响，列出复现步骤，然后给出一个建议的解决方案，所有这些都是纯文本的。

披露和限制信息
---------------

安全列表不是公开渠道。为此，请参见下面的协作。

一旦开发出了健壮的补丁，发布过程就开始了。对公开的缺陷的修复会立即发布。

尽管我们倾向于在未公开缺陷的修复可用时即发布补丁，但应报告者或受影响方的请求，
这可能会被推迟到发布过程开始后的7日内，如果根据缺陷的严重性需要更多的时间，
则可额外延长到14天。推迟发布修复的唯一有效原因是为了适应QA的逻辑和需要发布
协调的大规模部署。

虽然可能与受信任的个人共享受限信息以开发修复，但未经报告者许可，此类信息不会
与修复程序一起发布或发布在任何其他披露渠道上。这包括但不限于原始错误报告和
后续讨论（如有）、漏洞、CVE信息或报告者的身份。

换句话说，我们唯一感兴趣的是修复缺陷。提交给安全列表的所有其他资料以及对报告
的任何后续讨论，即使在解除限制之后，也将永久保密。

协调
------

对敏感缺陷（例如那些可能导致权限提升的缺陷）的修复可能需要与私有邮件列表
<linux-distros@vs.openwall.org>进行协调，以便分发供应商做好准备，在公开披露
上游补丁时发布一个已修复的内核。发行版将需要一些时间来测试建议的补丁，通常
会要求至少几天的限制，而供应商更新发布更倾向于周二至周四。若合适，安全团队
可以协助这种协调，或者报告者可以从一开始就包括linux发行版。在这种情况下，请
记住在电子邮件主题行前面加上“[vs]”，如linux发行版wiki中所述：
<http://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists>。

CVE分配
--------

安全团队通常不分配CVE，我们也不需要它们来进行报告或修复，因为这会使过程不必
要的复杂化，并可能耽误缺陷处理。如果报告者希望在公开披露之前分配一个CVE编号，
他们需要联系上述的私有linux-distros列表。当在提供补丁之前已有这样的CVE编号时，
如报告者愿意，最好在提交消息中提及它。

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

Linux内核安全团队不是一个正式的机构实体，因此无法签订任何保密协议。


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

:Original: Documentation/admin-guide/sysrq.rst

:翻译:

 黄军华 Junhua Huang <huang.junhua@zte.com.cn>

:校译:

 司延腾 Yanteng Si <siyanteng@loongson.cn>

.. _cn_admin-guide_sysrq:

Linux 魔法系统请求键骇客
========================

针对 sysrq.c 的文档说明

什么是魔法 SysRq 键？
~~~~~~~~~~~~~~~~~~~~~

它是一个你可以输入的具有魔法般的组合键。
无论内核在做什么，内核都会响应 SysRq 键的输入，除非内核完全卡死。

如何使能魔法 SysRq 键？
~~~~~~~~~~~~~~~~~~~~~~~

在配置内核时，我们需要设置 'Magic SysRq key (CONFIG_MAGIC_SYSRQ)' 为 'Y'。
当运行一个编译进 sysrq 功能的内核时，/proc/sys/kernel/sysrq 控制着被
SysRq 键调用的功能许可。这个文件的默认值由 CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE
配置符号设定，文件本身默认设置为 1。以下是 /proc/sys/kernel/sysrq 中可能的
值列表：

   -  0 - 完全不使能 SysRq 键
   -  1 - 使能 SysRq 键的全部功能
   - >1 - 对于允许的 SysRq 键功能的比特掩码（参见下面更详细的功能描述）::

          2 =   0x2 - 使能对控制台日志记录级别的控制
          4 =   0x4 - 使能对键盘的控制 (SAK, unraw)
          8 =   0x8 - 使能对进程的调试导出等
         16 =  0x10 - 使能同步命令
         32 =  0x20 - 使能重新挂载只读
         64 =  0x40 - 使能对进程的信号操作 (term, kill, oom-kill)
        128 =  0x80 - 允许重启、断电
        256 = 0x100 - 允许让所有实时任务变普通任务

你可以通过如下命令把值设置到这个文件中::

    echo "number" >/proc/sys/kernel/sysrq

这里被写入的 number 可以是 10 进制数，或者是带着 0x 前缀的 16 进制数。
CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE 必须是以 16 进制数写入。

注意，``/proc/sys/kernel/sysrq`` 的值只影响通过键盘触发 SySRq 的调用，对于
通过 ``/proc/sysrq-trigger`` 的任何操作调用都是允许的
（通过具有系统权限的用户）。

如何使用魔法 SysRq 键？
~~~~~~~~~~~~~~~~~~~~~~~

在 x86 架构上
	你可以按下键盘组合键 :kbd:`ALT-SysRq-<command key>`。

	.. note::
	   一些键盘可能没有标识 'SySRq' 键。'SySRq' 键也被当做 'Print Screen'键。
	   同时有些键盘无法处理同时按下这么多键，因此你可以先按下键盘 :kbd:`Alt` 键，
	   然后按下键盘 :kbd:`SysRq` 键，再释放键盘 :kbd:`SysRq` 键，之后按下键盘上命令键
	   :kbd:`<command key>`，最后释放所有键。

在 SPARC 架构上
	你可以按下键盘组合键 :kbd:`ALT-STOP-<command key>` 。

在串行控制台（只针对 PC 类型的标准串口）
        你可以发一个 ``BREAK`` ，然后在 5 秒内发送一个命令键，
	发送 ``BREAK`` 两次将被翻译为一个正常的 BREAK 操作。

在 PowerPC 架构上
	按下键盘组合键 :kbd:`ALT - Print Screen` （或者 :kbd:`F13`） - :kbd:`<命令键>` 。
        :kbd:`Print Screen` （或者 :kbd:`F13`） - :kbd:`<命令键>` 或许也能实现。

在其他架构上
	如果你知道其他架构的组合键，请告诉我，我可以把它们添加到这部分。

在所有架构上
	写一个字符到 /proc/sysrq-trigger 文件，例如::

		echo t > /proc/sysrq-trigger

这个命令键 :kbd:`<command key>` 是区分大小写的。

什么是命令键？
~~~~~~~~~~~~~~

=========== ================================================================
命令键	    功能
=========== ================================================================
``b``	    将立即重启系统，不会同步或者卸载磁盘。

``c``	    将执行系统 crash，如果配置了系统 crashdump，将执行 crashdump。

``d``	    显示所有持有的锁。

``e``	    发送 SIGTERM 信号给所有进程，除了 init 进程。

``f``	    将调用 oom killer 杀掉一个过度占用内存的进程，如果什么任务都没杀，
            也不会 panic。

``g``	    kgdb 使用（内核调试器）。

``h``	    将会显示帮助。（实际上除了这里列举的键，其他的都将显示帮助，
	    但是 ``h`` 容易记住）:-)

``i``	    发送 SIGKILL 给所有进程，除了 init 进程。

``j``	    强制性的 “解冻它” - 用于被 FIFREEZE ioctl 操作冻住的文件系统。

``k``	    安全访问秘钥(SAK)杀掉在当前虚拟控制台的所有程序，注意：参考
            下面 SAK 节重要论述。

``l``	    显示所有活动 cpu 的栈回溯。

``m``	    将导出当前内存信息到你的控制台。

``n``	    用于使所有实时任务变成普通任务。

``o``	    将关闭系统（如果配置和支持的话）。

``p``	    将导出当前寄存器和标志位到控制台。

``q``	    将导出每个 cpu 上所有已装备的高精度定时器（不是完整的
            time_list 文件显示的 timers）和所有时钟事件设备的详细信息。

``r``	    关闭键盘的原始模式，设置为转换模式。

``s``	    将尝试同步所有的已挂载文件系统。

``t``	    将导出当前所有任务列表和它们的信息到控制台。

``u``	    将尝试重新挂载已挂载文件系统为只读。

``v``	    强制恢复帧缓存控制台。
``v``	    触发 ETM 缓存导出 [ARM 架构特有]

``w``	    导出处于不可中断状态（阻塞）的任务。

``x``	    在 ppc/powerpc 架构上用于 xmon 接口。
            在 sparc64 架构上用于显示全局的 PMU（性能监控单元）寄存器。
            在 MIPS 架构上导出所有的 tlb 条目。

``y``	    显示全局 cpu 寄存器 [SPARC-64 架构特有]

``z``	    导出 ftrace 缓存信息

``0``-``9`` 设置控制台日志级别，该级别控制什么样的内核信息将被打印到你的
	    控制台。（比如 ``0`` ，将使得只有紧急信息，像 PANICs or OOPSes
	    才能到你的控制台。）
=========== ================================================================

好了，我能用他们做什么呢？
~~~~~~~~~~~~~~~~~~~~~~~~~~

嗯，当你的 X 服务端或者 svgalib 程序崩溃，unraw(r) 非原始模式命令键是非常
方便的。

sak(k)（安全访问秘钥）在你尝试登陆的同时，又想确保当前控制台没有可以获取你的
密码的特洛伊木马程序运行时是有用的。它会杀掉给定控制台的所有程序，这样你
就可以确认当前的登陆提示程序是实际来自 init 进程的程序，而不是某些特洛伊
木马程序。

.. important::

   在其实际的形式中，在兼容 C2 安全标准的系统上，它不是一个真正的 SAK，
   它也不应该误认为此。

似乎其他人发现其可以作为（系统终端联机键）当你想退出一个程序，
同时不会让你切换控制台的方法。（比如，X 服务端或者 svgalib 程序）

``reboot(b)`` 是个好方法，当你不能关闭机器时，它等同于按下"复位"按钮。

``crash(c)`` 可以用于手动触发一个 crashdump，当系统卡住时。
注意当 crashdump 机制不可用时，这个只是触发一个内核 crash。

``sync(s)`` 在拔掉可移动介质之前，或者在使用不提供优雅关机的
救援 shell 之后很方便 -- 它将确保你的数据被安全地写入磁盘。注意，在你看到
屏幕上出现 "OK" 和 "Done" 之前，同步还没有发生。

``umount(u)`` 可以用来标记文件系统正常卸载，从正在运行的系统角度来看，它们将
被重新挂载为只读。这个重新挂载动作直到你看到 "OK" 和 "Done" 信息出现在屏幕上
才算完成。

日志级别 ``0`` - ``9`` 用于当你的控制台被大量的内核信息冲击，你不想看见的时候。
选择 ``0`` 将禁止除了最紧急的内核信息外的所有的内核信息输出到控制台。（但是如果
syslogd/klogd 进程是运行的，它们仍将被记录。）

``term(e)`` 和 ``kill(i)`` 用于当你有些有点失控的进程，你无法通过其他方式杀掉
它们的时候，特别是它正在创建其他进程。

"just thaw ``it(j)`` " 用于当你的系统由于一个 FIFREEZE ioctl 调用而产生的文件
系统冻结，而导致的不响应时。

有的时候 SysRq 键在使用它之后，看起来像是“卡住”了，我能做些什么？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

这也会发生在我这，我发现轻敲键盘两侧的 shift、alt 和 control 键，然后再次敲击
一个无效的 SysRq 键序列可以解决问题。（比如，像键盘组合键 :kbd:`alt-sysrq-z` ）
切换到另一个虚拟控制台（键盘操作 :kbd:`ALT+Fn` ），然后再切回来应该也有帮助。

我敲击了 SysRq 键，但像是什么都没发生，发生了什么错误？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

有一些键盘对于 SysRq 键设置了不同的键值，而不是提前定义的 99
(查看在 ``include/uapi/linux/input-event-codes.h`` 文件中 ``KEY_SYSRQ`` 的定义)
或者就根本没有 SysRq 键。在这些场景下，执行 ``showkey -s`` 命令来找到一个合适
的扫描码序列，然后使用 ``setkeycodes <sequence> 99`` 命令映射这个序列值到通用
的 SysRq 键编码上（比如 ``setkeycodes e05b 99`` ）。最好将这个命令放在启动脚本
中。
哦，顺便说一句，你十秒钟不输入任何东西就将退出 “showkey”。

我想添加一个 SysRq 键事件到一个模块中，如何去做呢？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

为了注册一个基础函数到这个表中，首先你必须包含 ``include/linux/sysrq.h`` 头
文件，这个头文件定义了你所需要的所有东西。然后你必须创建一个 ``sysrq_key_op``
结构体，然后初始化它，使用如下内容，A） 你将使用的这个键的处理函数， B） 一个
help_msg 字符串，在 SysRq 键打印帮助信息时将打印出来，C） 一个 action_msg 字
符串，就在你的处理函数调用前打印出来。你的处理函数必须符合在 'sysrq.h' 文件中
的函数原型。

在 ``sysrq_key_op`` 结构体被创建后，你可以调用内核函数
``register_sysrq_key(int key, const struct sysrq_key_op *op_p);``，
该函数在表中的 'key' 对应位置内容是空的情况下，将通过 ``op_p`` 指针注册这个操作
函数到表中 'key' 对应位置上。在模块卸载的时候，你必须调用
``unregister_sysrq_key(int key, const struct sysrq_key_op *op_p)`` 函数，该函数
只有在当前该键对应的处理函数被注册到了 'key' 对应位置时，才会移除 'op_p' 指针
对应的键值操作函数。这是为了防止在你注册之后，该位置被改写的情况。

魔法 SysRq 键系统的工作原理是将键对应操作函数注册到键的操作查找表，
该表定义在 'drivers/tty/sysrq.c' 文件中。
该键表有许多在编译时候就注册进去的操作函数，但是是可变的。
并且有两个函数作为操作该表的接口被导出::

	register_sysrq_key 和 unregister_sysrq_key.

当然，永远不要在表中留下无效指针，即，当你的模块存在调用 register_sysrq_key()
函数，它一定要调用 unregister_sysrq_key() 来清除它使用过的 SysRq 键表条目。
表中的空指针是安全的。:)

如果对于某种原因，在 handle_sysrq 调用的处理函数中，你认为有必要调用
handle_sysrq 函数时，你必须意识到当前你处于一个锁中（你同时也处于一个中断处理
函数中，这意味着不能睡眠）。所以这时你必须使用 ``__handle_sysrq_nolock`` 替代。

当我敲击一个 SysRq 组合键时，只有标题打印出现在控制台？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SysRq 键的输出和所有其他控制台输出一样，受制于控制台日志级别控制。
这意味着，如果内核以发行版内核中常见的 "quiet" 方式启动，则输出可能不会出现在实际
的控制台上，即使它会出现在 dmesg 缓存中，也可以通过 dmesg 命令和 ``/proc/kmsg``
文件的消费访问到。作为一个特例，来自 sysrq 命令的标题行将被传递给所有控制台
使用者，就好像当前日志级别是最大的一样。如果只发出标题头，则几乎可以肯定内核日志
级别太低。如果你需要控制台上的输出，那么你将需要临时提高控制台日志级别，通过使用
键盘组合键 :kbd:`alt-sysrq-8` 或者::

    echo 8 > /proc/sysrq-trigger

在触发了你感兴趣的 SysRq 键命令后，记得恢复日志级别到正常情况。

我有很多问题时，可以请教谁？
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

请教在内核邮件列表上的人，邮箱：
	linux-kernel@vger.kernel.org

致谢
~~~~

- Mydraal <vulpyne@vulpyne.net> 撰写了该文件
- Adam Sulmicki <adam@cfar.umd.edu> 进行了更新
- Jeremy M. Dolan <jmd@turbogeek.org> 在 2001/01/28 10:15:59 进行了更新
- Crutcher Dunnavant <crutcher+kernel@datastacks.com> 添加键注册部分


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

:Original: :doc:`../../../admin-guide/tainted-kernels`

:译者:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

受污染的内核
-------------

当发生一些在稍后调查问题时可能相关的事件时，内核会将自己标记为“受污染
（tainted）”的。不用太过担心，大多数情况下运行受污染的内核没有问题；这些信息
主要在有人想调查某个问题时才有意义的，因为问题的真正原因可能是导致内核受污染
的事件。这就是为什么来自受污染内核的缺陷报告常常被开发人员忽略，因此请尝试用
未受污染的内核重现问题。

请注意，即使在您消除导致污染的原因（亦即卸载专有内核模块）之后，内核仍将保持
污染状态，以表示内核仍然不可信。这也是为什么内核在注意到内部问题（“kernel
bug”）、可恢复错误（“kernel oops”）或不可恢复错误（“kernel panic”）时会打印
受污染状态，并将有关此的调试信息写入日志 ``dmesg`` 输出。也可以通过
``/proc/`` 中的文件在运行时检查受污染的状态。

BUG、Oops或Panics消息中的污染标志
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在顶部以“CPU:”开头的一行中可以找到受污染的状态；内核是否受到污染和原因会显示
在进程ID（“PID:”）和触发事件命令的缩写名称（“Comm:”）之后::

	BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
	Oops: 0002 [#1] SMP PTI
	CPU: 0 PID: 4424 Comm: insmod Tainted: P        W  O      4.20.0-0.rc6.fc30 #1
	Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011
	RIP: 0010:my_oops_init+0x13/0x1000 [kpanic]
	[...]

如果内核在事件发生时没有被污染，您将在那里看到“Not-tainted:”；如果被污染，那
么它将是“Tainted:”以及字母或空格。在上面的例子中，它看起来是这样的::

	Tainted: P        W  O

下表解释了这些字符的含义。在本例中，由于加载了专有模块（ ``P`` ），出现了
警告（ ``W`` ），并且加载了外部构建的模块（ ``O`` ），所以内核早些时候受到
了污染。要解码其他字符，请使用下表。

解码运行时的污染状态
~~~~~~~~~~~~~~~~~~~~~

在运行时，您可以通过读取 ``cat /proc/sys/kernel/tainted`` 来查询受污染状态。
如果返回 ``0`` ，则内核没有受到污染；任何其他数字都表示受到污染的原因。解码
这个数字的最简单方法是使用脚本  ``tools/debugging/kernel-chktaint`` ，您的
发行版可能会将其作为名为 ``linux-tools`` 或 ``kernel-tools`` 的包的一部分提
供；如果没有，您可以从
`git.kernel.org <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/tools/debugging/kernel-chktaint>`_
网站下载此脚本并用 ``sh kernel-chktaint`` 执行，它会在上面引用的日志中有类似
语句的机器上打印这样的内容::

	Kernel is Tainted for following reasons:
	 * Proprietary module was loaded (#0)
	 * Kernel issued warning (#9)
	 * Externally-built ('out-of-tree') module was loaded  (#12)
	See Documentation/admin-guide/tainted-kernels.rst in the Linux kernel or
	 https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html for
	 a more details explanation of the various taint flags.
	Raw taint value as int/string: 4609/'P        W  O     '

你也可以试着自己解码这个数字。如果内核被污染的原因只有一个，那么这很简单，
在本例中您可以通过下表找到数字。如果你需要解码有多个原因的数字，因为它是一
个位域（bitfield），其中每个位表示一个特定类型的污染的存在或不存在，最好让
前面提到的脚本来处理。但是如果您需要快速看一下，可以使用这个shell命令来检查
设置了哪些位::

	$ for i in $(seq 18); do echo $(($i-1)) $(($(cat /proc/sys/kernel/tainted)>>($i-1)&1));done

污染状态代码表
~~~~~~~~~~~~~~~

===  =====  ======  ========================================================
 位  日志     数字  内核被污染的原因
===  =====  ======  ========================================================
  0   G/P        1  已加载专用模块
  1   _/F        2  模块被强制加载
  2   _/S        4  内核运行在不合规范的系统上
  3   _/R        8  模块被强制卸载
  4   _/M       16  处理器报告了机器检测异常（MCE）
  5   _/B       32  引用了错误的页或某些意外的页标志
  6   _/U       64  用户空间应用程序请求的污染
  7   _/D      128  内核最近死机了，即曾出现OOPS或BUG
  8   _/A      256  ACPI表被用户覆盖
  9   _/W      512  内核发出警告
 10   _/C     1024  已加载staging驱动程序
 11   _/I     2048  已应用平台固件缺陷的解决方案
 12   _/O     4096  已加载外部构建（“树外”）模块
 13   _/E     8192  已加载未签名的模块
 14   _/L    16384  发生软锁定
 15   _/K    32768  内核已实时打补丁
 16   _/X    65536  备用污染，为发行版定义并使用
 17   _/T   131072  内核是用结构随机化插件构建的
===  =====  ======  ========================================================

注：字符 ``_`` 表示空白，以便于阅读表。

污染的更详细解释
~~~~~~~~~~~~~~~~~

 0)  ``G`` 加载的所有模块都有GPL或兼容许可证， ``P`` 加载了任何专有模块。
     没有MODULE_LICENSE（模块许可证）或MODULE_LICENSE未被insmod认可为GPL
     兼容的模块被认为是专有的。

 1)  ``F`` 任何模块被 ``insmod -f`` 强制加载， ``' '`` 所有模块正常加载。

 2)  ``S`` 内核运行在不合规范的处理器或系统上：硬件已运行在不受支持的配置中，
     因此无法保证正确执行。内核将被污染，例如：

     - 在x86上：PAE是通过intel CPU（如Pentium M）上的forcepae强制执行的，这些
       CPU不报告PAE，但可能有功能实现，SMP内核在非官方支持的SMP Athlon CPU上
       运行，MSR被暴露到用户空间中。
     - 在arm上：在某些CPU（如Keystone 2）上运行的内核，没有启用某些内核特性。
     - 在arm64上：CPU之间存在不匹配的硬件特性，引导加载程序以不同的模式引导CPU。
     - 某些驱动程序正在被用在不受支持的体系结构上（例如x86_64以外的其他系统
       上的scsi/snic，非x86/x86_64/itanium上的scsi/ips，已经损坏了arm64上
       irqchip/irq-gic的固件设置…）。

 3)  ``R`` 模块被 ``rmmod -f`` 强制卸载， ``' '`` 所有模块都正常卸载。

 4)  ``M`` 任何处理器报告了机器检测异常， ``' '`` 未发生机器检测异常。

 5)  ``B`` 页面释放函数发现错误的页面引用或某些意外的页面标志。这表示硬件问题
     或内核错误；日志中应该有其他信息指示发生此污染的原因。

 6)  ``U`` 用户或用户应用程序特意请求设置受污染标志，否则应为 ``' '`` 。

 7)  ``D`` 内核最近死机了，即出现了OOPS或BUG。

 8)  ``A`` ACPI表被重写。

 9)  ``W`` 内核之前已发出过警告（尽管有些警告可能会设置更具体的污染标志）。

 10) ``C`` 已加载staging驱动程序。

 11) ``I`` 内核正在处理平台固件（BIOS或类似软件）中的严重错误。

 12) ``O`` 已加载外部构建（“树外”）模块。

 13) ``E`` 在支持模块签名的内核中加载了未签名的模块。

 14) ``L`` 系统上先前发生过软锁定。

 15) ``K`` 内核已经实时打了补丁。

 16) ``X`` 备用污染，由Linux发行版定义和使用。

 17) ``T`` 内核构建时使用了randstruct插件，它可以有意生成非常不寻常的内核结构
     布局（甚至是性能病态的布局），这在调试时非常有用。于构建时设置。


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

:Original: Documentation/admin-guide/unicode.rst

:译者:

 吴想成 Wu XiangCheng <bobwxc@email.cn>

Unicode（统一码）支持
======================

	（英文版）上次更新：2005-01-17，版本号 1.4

此文档由H. Peter Anvin <unicode@lanana.org>管理，是Linux注册名称与编号管理局
（Linux Assigned Names And Numbers Authority，LANANA）项目的一部分。
现行版本请见：

	http://www.lanana.org/docs/unicode/admin-guide/unicode.rst

简介
-----

Linux内核代码已被重写以使用Unicode来将字符映射到字体。下载一个Unicode到字体
（Unicode-to-font）表，八位字符集与UTF-8模式都将改用此字体来显示。

这微妙地改变了八位字符表的语义。现在的四个字符表是：

=============== =============================== ================
映射代号        映射名称                        Escape代码 (G0)
=============== =============================== ================
LAT1_MAP        Latin-1 (ISO 8859-1)            ESC ( B
GRAF_MAP        DEC VT100 pseudographics        ESC ( 0
IBMPC_MAP       IBM code page 437               ESC ( U
USER_MAP        User defined                    ESC ( K
=============== =============================== ================

特别是 ESC ( U 不再是“直通字体”，因为字体可能与IBM字符集完全不同。
例如，即使加载了一个Latin-1字体，也允许使用块图形（block graphics）。

请注意，尽管这些代码与ISO 2022类似，但这些代码及其用途都与ISO 2022不匹配；
Linux有两个八位代码（G0和G1），而ISO 2022有四个七位代码（G0-G3）。

根据Unicode标准/ISO 10646，U+F000到U+F8FF被保留用于操作系统范围内的分配
（Unicode标准将其称为“团体区域（Corporate Zone）”，因为这对于Linux是不准确
的，所以我们称之为“Linux区域”）。选择U+F000作为起点，因为它允许直接映射
区域以2的大倍数开始（以防需要1024或2048个字符的字体）。这就留下U+E000到
U+EFFF作为最终用户区。

[v1.2]：Unicodes范围从U+F000到U+F7FF已经被硬编码为直接映射到加载的字体，
绕过了翻译表。用户定义的映射现在默认为U+F000到U+F0FF，模拟前述行为。实际上，
此范围可能较短；例如，vgacon只能处理256字符（U+F000..U+F0FF）或512字符
（U+F000..U+F1FF）字体。

Linux 区域中定义的实际字符
---------------------------

此外，还定义了Unicode 1.1.4中不存在的以下字符；这些字符由DEC VT图形映射使用。
[v1.2]此用法已过时，不应再使用；请参见下文。

====== ======================================
U+F800 DEC VT GRAPHICS HORIZONTAL LINE SCAN 1
U+F801 DEC VT GRAPHICS HORIZONTAL LINE SCAN 3
U+F803 DEC VT GRAPHICS HORIZONTAL LINE SCAN 7
U+F804 DEC VT GRAPHICS HORIZONTAL LINE SCAN 9
====== ======================================

DEC VT220使用6x10字符矩阵，这些字符在DEC VT图形字符集中形成一个平滑的过渡。
我省略了扫描5行，因为它也被用作块图形字符，因此被编码为U+2500 FORMS LIGHT
HORIZONTAL。

[v1.3]：这些字符已正式添加到Unicode 3.2.0中；它们在U+23BA、U+23BB、U+23BC、
U+23BD处添加。Linux现在使用新值。

[v1.2]：添加了以下字符来表示常见的键盘符号，这些符号不太可能被添加到Unicode
中，因为它们非常讨厌地取决于特定供应商。当然，这是糟糕设计的一个好例子。

====== ======================================
U+F810 KEYBOARD SYMBOL FLYING FLAG
U+F811 KEYBOARD SYMBOL PULLDOWN MENU
U+F812 KEYBOARD SYMBOL OPEN APPLE
U+F813 KEYBOARD SYMBOL SOLID APPLE
====== ======================================

克林贡（Klingon）语支持
------------------------

1996年，Linux是世界上第一个添加对人工语言克林贡支持的操作系统，克林贡是由
Marc Okrand为《星际迷航》电视连续剧创造的。这种编码后来被征募Unicode注册表
（ConScript Unicode Registry，CSUR）采用，并建议（但最终被拒绝）纳入Unicode
平面一。不过，它仍然是Linux区域中的Linux/CSUR私有分配。

这种编码已经得到克林贡语言研究所（Klingon Language Institute）的认可。
有关更多信息，请联系他们：

	http://www.kli.org/

由于Linux CZ开头部分的字符大多是dingbats/symbols/forms类型，而且这是一种
语言，因此根据标准Unicode惯例，我将它放置在16单元的边界上。

.. note::

  这个范围现在由征募Unicode注册表正式管理。规范性引用文件为：

	https://www.evertype.com/standards/csur/klingon.html

克林贡语有一个26个字符的字母表，一个10位数的位置数字书写系统，从左到右
，从上到下书写。

克林贡字母的几种字形已经被提出。但是由于这组符号看起来始终是一致的，只有实际
的形状不同，因此按照标准Unicode惯例，这些差异被认为是字体变体。

======	=======================================================
U+F8D0	KLINGON LETTER A
U+F8D1	KLINGON LETTER B
U+F8D2	KLINGON LETTER CH
U+F8D3	KLINGON LETTER D
U+F8D4	KLINGON LETTER E
U+F8D5	KLINGON LETTER GH
U+F8D6	KLINGON LETTER H
U+F8D7	KLINGON LETTER I
U+F8D8	KLINGON LETTER J
U+F8D9	KLINGON LETTER L
U+F8DA	KLINGON LETTER M
U+F8DB	KLINGON LETTER N
U+F8DC	KLINGON LETTER NG
U+F8DD	KLINGON LETTER O
U+F8DE	KLINGON LETTER P
U+F8DF	KLINGON LETTER Q
	- Written <q> in standard Okrand Latin transliteration
U+F8E0	KLINGON LETTER QH
	- Written <Q> in standard Okrand Latin transliteration
U+F8E1	KLINGON LETTER R
U+F8E2	KLINGON LETTER S
U+F8E3	KLINGON LETTER T
U+F8E4	KLINGON LETTER TLH
U+F8E5	KLINGON LETTER U
U+F8E6	KLINGON LETTER V
U+F8E7	KLINGON LETTER W
U+F8E8	KLINGON LETTER Y
U+F8E9	KLINGON LETTER GLOTTAL STOP

U+F8F0	KLINGON DIGIT ZERO
U+F8F1	KLINGON DIGIT ONE
U+F8F2	KLINGON DIGIT TWO
U+F8F3	KLINGON DIGIT THREE
U+F8F4	KLINGON DIGIT FOUR
U+F8F5	KLINGON DIGIT FIVE
U+F8F6	KLINGON DIGIT SIX
U+F8F7	KLINGON DIGIT SEVEN
U+F8F8	KLINGON DIGIT EIGHT
U+F8F9	KLINGON DIGIT NINE

U+F8FD	KLINGON COMMA
U+F8FE	KLINGON FULL STOP
U+F8FF	KLINGON SYMBOL FOR EMPIRE
======	=======================================================

其他虚构和人工字母
-------------------

自从分配了克林贡Linux Unicode块之后，John Cowan <jcowan@reutershealth.com>
和 Michael Everson <everson@evertype.com> 建立了一个虚构和人工字母的注册表。
征募Unicode注册表请访问：

	https://www.evertype.com/standards/csur/

所使用的范围位于最终用户区域的低端，因此无法进行规范化分配，但建议希望对虚构
字母进行编码的人员使用这些代码，以实现互操作性。对于克林贡语，CSUR采用了Linux
编码。CSUR的人正在推动将Tengwar和Cirth添加到Unicode平面一；将克林贡添加到
Unicode平面一被拒绝，因此上述编码仍然是官方的。


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

处理器体系结构
==============

以下文档提供了具体架构实现的编程细节。

.. toctree::
   :maxdepth: 2

   mips/index
   arm64/index
   riscv/index
   openrisc/index
   parisc/index
   loongarch/index

TODOList:

* arm/index
* ia64/index
* m68k/index
* nios2/index
* powerpc/index
* s390/index
* sh/index
* sparc/index
* x86/index
* xtensa/index


code:
Chinese translated version of Documentation/arm/booting.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: Russell King <linux@arm.linux.org.uk>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
Documentation/arm/booting.rst 的中文翻译

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

英文版维护者： Russell King <linux@arm.linux.org.uk>
中文版维护者： 傅炜  Fu Wei <tekkamanninja@gmail.com>
中文版翻译者： 傅炜  Fu Wei <tekkamanninja@gmail.com>
中文版校译者： 傅炜  Fu Wei <tekkamanninja@gmail.com>

以下为正文
---------------------------------------------------------------------

			启动 ARM Linux
			==============

作者：Russell King
日期：2002年5月18日

以下文档适用于 2.4.18-rmk6 及以上版本。

为了启动 ARM Linux，你需要一个引导装载程序（boot loader），
它是一个在主内核启动前运行的一个小程序。引导装载程序需要初始化各种
设备，并最终调用 Linux 内核，将信息传递给内核。

从本质上讲，引导装载程序应提供（至少）以下功能：

1、设置和初始化 RAM。
2、初始化一个串口。
3、检测机器的类型（machine type）。
4、设置内核标签列表（tagged list）。
5、调用内核映像。

1、设置和初始化 RAM
-------------------

现有的引导加载程序:		强制
新开发的引导加载程序:		强制

引导装载程序应该找到并初始化系统中所有内核用于保持系统变量数据的 RAM。
这个操作的执行是设备依赖的。（它可能使用内部算法来自动定位和计算所有
RAM，或可能使用对这个设备已知的 RAM 信息，还可能使用任何引导装载程序
设计者想到的匹配方法。）

2、初始化一个串口
-----------------------------

现有的引导加载程序:		可选、建议
新开发的引导加载程序:		可选、建议

引导加载程序应该初始化并使能一个目标板上的串口。这允许内核串口驱动
自动检测哪个串口用于内核控制台。(一般用于调试或与目标板通信。)

作为替代方案，引导加载程序也可以通过标签列表传递相关的'console='
选项给内核以指定某个串口，而串口数据格式的选项在以下文档中描述：

       Documentation/admin-guide/kernel-parameters.rst。

3、检测机器类型
--------------------------

现有的引导加载程序:		可选
新开发的引导加载程序:		强制

引导加载程序应该通过某些方式检测自身所处的机器类型。这是一个硬件
代码或通过查看所连接的硬件用某些算法得到，这些超出了本文档的范围。
引导加载程序最终必须能提供一个 MACH_TYPE_xxx 值给内核。
(详见 linux/arch/arm/tools/mach-types )。

4、设置启动数据
------------------

现有的引导加载程序:		可选、强烈建议
新开发的引导加载程序:		强制

引导加载程序必须提供标签列表或者 dtb 映像以传递配置数据给内核。启动
数据的物理地址通过寄存器 r2 传递给内核。

4a、设置内核标签列表
--------------------------------

bootloader 必须创建和初始化内核标签列表。一个有效的标签列表以
ATAG_CORE 标签开始，并以 ATAG_NONE 标签结束。ATAG_CORE 标签可以是
空的，也可以是非空。一个空 ATAG_CORE 标签其 size 域设置为
‘2’(0x00000002)。ATAG_NONE 标签的 size 域必须设置为零。

在列表中可以保存任意数量的标签。对于一个重复的标签是追加到之前标签
所携带的信息之后，还是会覆盖原来的信息，是未定义的。某些标签的行为
是前者，其他是后者。

bootloader 必须传递一个系统内存的位置和最小值，以及根文件系统位置。
因此，最小的标签列表如下所示：

		+-----------+
基地址 ->	| ATAG_CORE |  |
		+-----------+  |
		| ATAG_MEM  |  | 地址增长方向
		+-----------+  |
		| ATAG_NONE |  |
		+-----------+  v

标签列表应该保存在系统的 RAM 中。

标签列表必须置于内核自解压和 initrd'bootp' 程序都不会覆盖的内存区。
建议放在 RAM 的头 16KiB 中。

4b、设置设备树
-------------------------

bootloader 必须以 64bit 地址对齐的形式加载一个设备树映像(dtb)到系统
RAM 中，并用启动数据初始化它。dtb 格式在文档
https://www.devicetree.org/specifications/ 中。内核将会在
dtb 物理地址处查找 dtb 魔数值（0xd00dfeed），以确定 dtb 是否已经代替
标签列表被传递进来。

bootloader 必须传递一个系统内存的位置和最小值，以及根文件系统位置。
dtb 必须置于内核自解压不会覆盖的内存区。建议将其放置于 RAM 的头 16KiB
中。但是不可将其放置于“0”物理地址处，因为内核认为：r2 中为 0，意味着
没有标签列表和 dtb 传递过来。

5、调用内核映像
---------------------------

现有的引导加载程序:		强制
新开发的引导加载程序:		强制

调用内核映像 zImage 有两个选择。如果 zImge 保存在 flash 中，且是为了
在 flash 中直接运行而被正确链接的。这样引导加载程序就可以在 flash 中
直接调用 zImage。

zImage 也可以被放在系统 RAM（任意位置）中被调用。注意：内核使用映像
基地址的前 16KB RAM 空间来保存页表。建议将映像置于 RAM 的 32KB 处。

对于以上任意一种情况，都必须符合以下启动状态：

- 停止所有 DMA 设备，这样内存数据就不会因为虚假网络包或磁盘数据而被破坏。
  这可能可以节省你许多的调试时间。

- CPU 寄存器配置
  r0 = 0，
  r1 = （在上面 3 中获取的）机器类型码。
  r2 = 标签列表在系统 RAM 中的物理地址，或
       设备树块(dtb)在系统 RAM 中的物理地址

- CPU 模式
  所有形式的中断必须被禁止 (IRQs 和 FIQs)
  CPU 必须处于 SVC 模式。(对于 Angel 调试有特例存在)

- 缓存，MMUs
  MMU 必须关闭。
  指令缓存开启或关闭都可以。
  数据缓存必须关闭。

- 引导加载程序应该通过直接跳转到内核映像的第一条指令来调用内核映像。

  对于支持 ARM 指令集的 CPU，跳入内核入口时必须处在 ARM 状态，即使
  对于 Thumb-2 内核也是如此。

  对于仅支持 Thumb 指令集的 CPU，比如 Cortex-M 系列的 CPU，跳入
  内核入口时必须处于 Thumb 状态。


code:
Chinese translated version of Documentation/arm/kernel_user_helpers.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: Nicolas Pitre <nicolas.pitre@linaro.org>
		Dave Martin <dave.martin@linaro.org>
Chinese maintainer: Fu Wei <tekkamanninja@gmail.com>
---------------------------------------------------------------------
Documentation/arm/kernel_user_helpers.rst 的中文翻译

如果想评论或更新本文的内容，请直接联系原文档的维护者。如果你使用英文
交流有困难的话，也可以向中文版维护者求助。如果本翻译更新不及时或者翻
译存在问题，请联系中文版维护者。
英文版维护者： Nicolas Pitre <nicolas.pitre@linaro.org>
		Dave Martin <dave.martin@linaro.org>
中文版维护者： 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版翻译者： 傅炜 Fu Wei <tekkamanninja@gmail.com>
中文版校译者： 宋冬生 Dongsheng Song <dongshneg.song@gmail.com>
		傅炜 Fu Wei <tekkamanninja@gmail.com>

以下为正文
---------------------------------------------------------------------
内核提供的用户空间辅助代码
=========================

在内核内存空间的固定地址处，有一个由内核提供并可从用户空间访问的代码
段。它用于向用户空间提供因在许多 ARM CPU 中未实现的特性和/或指令而需
内核提供帮助的某些操作。这些代码直接在用户模式下执行的想法是为了获得
最佳效率，但那些与内核计数器联系过于紧密的部分，则被留给了用户库实现。
事实上，此代码甚至可能因不同的 CPU 而异，这取决于其可用的指令集或它
是否为 SMP 系统。换句话说，内核保留在不作出警告的情况下根据需要更改
这些代码的权利。只有本文档描述的入口及其结果是保证稳定的。

这与完全成熟的 VDSO 实现不同（但两者并不冲突），尽管如此，VDSO 可阻止
某些通过常量高效跳转到那些代码段的汇编技巧。且由于那些代码段在返回用户
代码前仅使用少量的代码周期，则一个 VDSO 间接远程调用将会在这些简单的
操作上增加一个可测量的开销。

在对那些拥有原生支持的新型处理器进行代码优化时，仅在已为其他操作使用
了类似的新增指令，而导致二进制结果已与早期 ARM 处理器不兼容的情况下，
用户空间才应绕过这些辅助代码，并在内联函数中实现这些操作（无论是通过
编译器在代码中直接放置，还是作为库函数调用实现的一部分）。也就是说，
如果你编译的代码不会为了其他目的使用新指令，则不要仅为了避免使用这些
内核辅助代码，导致二进制程序无法在早期处理器上运行。

新的辅助代码可能随着时间的推移而增加，所以新内核中的某些辅助代码在旧
内核中可能不存在。因此，程序必须在对任何辅助代码调用假设是安全之前，
检测 __kuser_helper_version 的值（见下文）。理想情况下，这种检测应该
只在进程启动时执行一次；如果内核版本不支持所需辅助代码，则该进程可尽早
中止执行。

kuser_helper_version
--------------------

位置:	0xffff0ffc

参考声明:

  extern int32_t __kuser_helper_version;

定义:

  这个区域包含了当前运行内核实现的辅助代码版本号。用户空间可以通过读
  取此版本号以确定特定的辅助代码是否存在。

使用范例:

#define __kuser_helper_version (*(int32_t *)0xffff0ffc)

void check_kuser_version(void)
{
	if (__kuser_helper_version < 2) {
		fprintf(stderr, "can't do atomic operations, kernel too old\n");
		abort();
	}
}

注意:

  用户空间可以假设这个域的值不会在任何单个进程的生存期内改变。也就
  是说，这个域可以仅在库的初始化阶段或进程启动阶段读取一次。

kuser_get_tls
-------------

位置:	0xffff0fe0

参考原型:

  void * __kuser_get_tls(void);

输入:

  lr = 返回地址

输出:

  r0 = TLS 值

被篡改的寄存器:

  无

定义:

  获取之前通过 __ARM_NR_set_tls 系统调用设置的 TLS 值。

使用范例:

typedef void * (__kuser_get_tls_t)(void);
#define __kuser_get_tls (*(__kuser_get_tls_t *)0xffff0fe0)

void foo()
{
	void *tls = __kuser_get_tls();
	printf("TLS = %p\n", tls);
}

注意:

  - 仅在 __kuser_helper_version >= 1 时，此辅助代码存在
    （从内核版本 2.6.12 开始）。

kuser_cmpxchg
-------------

位置:	0xffff0fc0

参考原型:

  int __kuser_cmpxchg(int32_t oldval, int32_t newval, volatile int32_t *ptr);

输入:

  r0 = oldval
  r1 = newval
  r2 = ptr
  lr = 返回地址

输出:

  r0 = 成功代码 (零或非零)
  C flag = 如果 r0 == 0 则置 1，如果 r0 != 0 则清零。

被篡改的寄存器:

  r3, ip, flags

定义:

  仅在 *ptr 为 oldval 时原子保存 newval 于 *ptr 中。
  如果 *ptr 被改变，则返回值为零，否则为非零值。
  如果 *ptr 被改变，则 C flag 也会被置 1，以实现调用代码中的汇编
  优化。

使用范例:

typedef int (__kuser_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
#define __kuser_cmpxchg (*(__kuser_cmpxchg_t *)0xffff0fc0)

int atomic_add(volatile int *ptr, int val)
{
	int old, new;

	do {
		old = *ptr;
		new = old + val;
	} while(__kuser_cmpxchg(old, new, ptr));

	return new;
}

注意:

  - 这个例程已根据需要包含了内存屏障。

  - 仅在 __kuser_helper_version >= 2 时，此辅助代码存在
    （从内核版本 2.6.12 开始）。

kuser_memory_barrier
--------------------

位置:	0xffff0fa0

参考原型:

  void __kuser_memory_barrier(void);

输入:

  lr = 返回地址

输出:

  无

被篡改的寄存器:

  无

定义:

  应用于任何需要内存屏障以防止手动数据修改带来的一致性问题，以及
  __kuser_cmpxchg 中。

使用范例:

typedef void (__kuser_dmb_t)(void);
#define __kuser_dmb (*(__kuser_dmb_t *)0xffff0fa0)

注意:

  - 仅在 __kuser_helper_version >= 3 时，此辅助代码存在
    （从内核版本 2.6.15 开始）。

kuser_cmpxchg64
---------------

位置:	0xffff0f60

参考原型:

  int __kuser_cmpxchg64(const int64_t *oldval,
                        const int64_t *newval,
                        volatile int64_t *ptr);

输入:

  r0 = 指向 oldval
  r1 = 指向 newval
  r2 = 指向目标值
  lr = 返回地址

输出:

  r0 = 成功代码 (零或非零)
  C flag = 如果 r0 == 0 则置 1，如果 r0 != 0 则清零。

被篡改的寄存器:

  r3, lr, flags

定义:

  仅在 *ptr 等于 *oldval 指向的 64 位值时，原子保存 *newval
  指向的 64 位值于 *ptr 中。如果 *ptr 被改变，则返回值为零，
  否则为非零值。

  如果 *ptr 被改变，则 C flag 也会被置 1，以实现调用代码中的汇编
  优化。

使用范例:

typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
                                  const int64_t *newval,
                                  volatile int64_t *ptr);
#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)

int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
{
	int64_t old, new;

	do {
		old = *ptr;
		new = old + val;
	} while(__kuser_cmpxchg64(&old, &new, ptr));

	return new;
}

注意:

  - 这个例程已根据需要包含了内存屏障。

  - 由于这个过程的代码长度（此辅助代码跨越 2 个常规的 kuser “槽”），
    因此 0xffff0f80 不被作为有效的入口点。

  - 仅在 __kuser_helper_version >= 5 时，此辅助代码存在
    （从内核版本 3.1 开始）。


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

:Original: :ref:`Documentation/arm64/amu.rst <amu_index>`

Translator: Bailu Lin <bailu.lin@vivo.com>

==================================
AArch64 Linux 中扩展的活动监控单元
==================================

作者: Ionela Voinescu <ionela.voinescu@arm.com>

日期: 2019-09-10

本文档简要描述了 AArch64 Linux 支持的活动监控单元的规范。

架构总述
--------

活动监控是 ARMv8.4 CPU 架构引入的一个可选扩展特性。

活动监控单元(在每个 CPU 中实现)为系统管理提供了性能计数器。既可以通
过系统寄存器的方式访问计数器，同时也支持外部内存映射的方式访问计数器。

AMUv1 架构实现了一个由4个固定的64位事件计数器组成的计数器组。

  - CPU 周期计数器：同 CPU 的频率增长
  - 常量计数器：同固定的系统时钟频率增长
  - 淘汰指令计数器: 同每次架构指令执行增长
  - 内存停顿周期计数器：计算由在时钟域内的最后一级缓存中未命中而引起
    的指令调度停顿周期数

当处于 WFI 或者 WFE 状态时，计数器不会增长。

AMU 架构提供了一个高达16位的事件计数器空间，未来新的 AMU 版本中可能
用它来实现新增的事件计数器。

另外，AMUv1 实现了一个多达16个64位辅助事件计数器的计数器组。

冷复位时所有的计数器会清零。

基本支持
--------

内核可以安全地运行在支持 AMU 和不支持 AMU 的 CPU 组合中。
因此，当配置 CONFIG_ARM64_AMU_EXTN 后我们无条件使能后续
(secondary or hotplugged) CPU 检测和使用这个特性。

当在 CPU 上检测到该特性时，我们会标记为特性可用但是不能保证计数器的功能，
仅表明有扩展属性。

固件(代码运行在高异常级别，例如 arm-tf )需支持以下功能：

 - 提供低异常级别(EL2 和 EL1)访问 AMU 寄存器的能力。
 - 使能计数器。如果未使能，它的值应为 0。
 - 在从电源关闭状态启动 CPU 前或后保存或者恢复计数器。

当使用使能了该特性的内核启动但固件损坏时，访问计数器寄存器可能会遭遇
panic 或者死锁。即使未发现这些症状，计数器寄存器返回的数据结果并不一
定能反映真实情况。通常，计数器会返回 0，表明他们未被使能。

如果固件没有提供适当的支持最好关闭 CONFIG_ARM64_AMU_EXTN。
值得注意的是，出于安全原因，不要绕过 AMUSERRENR_EL0 设置而捕获从
EL0(用户空间) 访问 EL1(内核空间)。 因此，固件应该确保访问 AMU寄存器
不会困在 EL2或EL3。

AMUv1 的固定计数器可以通过如下系统寄存器访问：

 - SYS_AMEVCNTR0_CORE_EL0
 - SYS_AMEVCNTR0_CONST_EL0
 - SYS_AMEVCNTR0_INST_RET_EL0
 - SYS_AMEVCNTR0_MEM_STALL_EL0

特定辅助计数器可以通过 SYS_AMEVCNTR1_EL0(n) 访问，其中n介于0到15。

详细信息定义在目录：arch/arm64/include/asm/sysreg.h。

用户空间访问
------------

由于以下原因，当前禁止从用户空间访问 AMU 的寄存器：

  - 安全因数：可能会暴露处于安全模式执行的代码信息。
  - 意愿：AMU 是用于系统管理的。

同样，该功能对用户空间不可见。

虚拟化
------

由于以下原因，当前禁止从 KVM 客户端的用户空间(EL0)和内核空间(EL1)
访问 AMU 的寄存器：

  - 安全因数：可能会暴露给其他客户端或主机端执行的代码信息。

任何试图访问 AMU 寄存器的行为都会触发一个注册在客户端的未定义异常。