diff options
Diffstat (limited to 'Documentation/translations/zh_CN')
26 files changed, 1255 insertions, 124 deletions
diff --git a/Documentation/translations/zh_CN/PCI/msi-howto.rst b/Documentation/translations/zh_CN/PCI/msi-howto.rst index 1b9b5ea790d8..95baadf767e4 100644 --- a/Documentation/translations/zh_CN/PCI/msi-howto.rst +++ b/Documentation/translations/zh_CN/PCI/msi-howto.rst @@ -88,7 +88,7 @@ MSI功能。 如果设备对最小数量的向量有要求,驱动程序可以传递一个min_vecs参数,设置为这个限制, 如果PCI核不能满足最小数量的向量,将返回-ENOSPC。 -flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_LEGACY, PCI_IRQ_MSI, +flags参数用来指定设备和驱动程序可以使用哪种类型的中断(PCI_IRQ_INTX, PCI_IRQ_MSI, PCI_IRQ_MSIX)。一个方便的短语(PCI_IRQ_ALL_TYPES)也可以用来要求任何可能的中断类型。 如果PCI_IRQ_AFFINITY标志被设置,pci_alloc_irq_vectors()将把中断分散到可用的CPU上。 diff --git a/Documentation/translations/zh_CN/PCI/pci.rst b/Documentation/translations/zh_CN/PCI/pci.rst index 83c2a41d38d3..347f5c3f5ce9 100644 --- a/Documentation/translations/zh_CN/PCI/pci.rst +++ b/Documentation/translations/zh_CN/PCI/pci.rst @@ -304,7 +304,7 @@ MSI-X可以分配几个单独的向量。 的PCI_IRQ_MSI和/或PCI_IRQ_MSIX标志来启用MSI功能。这将导致PCI支持将CPU向量数 据编程到PCI设备功能寄存器中。许多架构、芯片组或BIOS不支持MSI或MSI-X,调用 ``pci_alloc_irq_vectors`` 时只使用PCI_IRQ_MSI和PCI_IRQ_MSIX标志会失败, -所以尽量也要指定 ``PCI_IRQ_LEGACY`` 。 +所以尽量也要指定 ``PCI_IRQ_INTX`` 。 对MSI/MSI-X和传统INTx有不同中断处理程序的驱动程序应该在调用 ``pci_alloc_irq_vectors`` 后根据 ``pci_dev``结构体中的 ``msi_enabled`` diff --git a/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst index 17b9949d9b43..da2745464ece 100644 --- a/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst +++ b/Documentation/translations/zh_CN/admin-guide/mm/damon/usage.rst @@ -344,7 +344,7 @@ debugfs接口 :ref:`sysfs接口<sysfs_interface>`。 DAMON导出了八个文件, ``attrs``, ``target_ids``, ``init_regions``, -``schemes``, ``monitor_on``, ``kdamond_pid``, ``mk_contexts`` 和 +``schemes``, ``monitor_on_DEPRECATED``, ``kdamond_pid``, ``mk_contexts`` 和 ``rm_contexts`` under its debugfs directory, ``<debugfs>/damon/``. @@ -521,15 +521,15 @@ DAMON导出了八个文件, ``attrs``, ``target_ids``, ``init_regions``, 开关 ---- -除非你明确地启动监测,否则如上所述的文件设置不会产生效果。你可以通过写入和读取 ``monitor_on`` +除非你明确地启动监测,否则如上所述的文件设置不会产生效果。你可以通过写入和读取 ``monitor_on_DEPRECATED`` 文件来启动、停止和检查监测的当前状态。写入 ``on`` 该文件可以启动对有属性的目标的监测。写入 ``off`` 该文件则停止这些目标。如果每个目标进程被终止,DAMON也会停止。下面的示例命令开启、关 闭和检查DAMON的状态:: # cd <debugfs>/damon - # echo on > monitor_on - # echo off > monitor_on - # cat monitor_on + # echo on > monitor_on_DEPRECATED + # echo off > monitor_on_DEPRECATED + # cat monitor_on_DEPRECATED off 请注意,当监测开启时,你不能写到上述的debugfs文件。如果你在DAMON运行时写到这些文件,将会返 @@ -543,11 +543,11 @@ DAMON通过一个叫做kdamond的内核线程来进行请求监测。你可以 得该线程的 ``pid`` 。当监测被 ``关闭`` 时,读取该文件不会返回任何信息:: # cd <debugfs>/damon - # cat monitor_on + # cat monitor_on_DEPRECATED off # cat kdamond_pid none - # echo on > monitor_on + # echo on > monitor_on_DEPRECATED # cat kdamond_pid 18594 @@ -574,7 +574,7 @@ DAMON通过一个叫做kdamond的内核线程来进行请求监测。你可以 # ls foo # ls: cannot access 'foo': No such file or directory -注意, ``mk_contexts`` 、 ``rm_contexts`` 和 ``monitor_on`` 文件只在根目录下。 +注意, ``mk_contexts`` 、 ``rm_contexts`` 和 ``monitor_on_DEPRECATED`` 文件只在根目录下。 监测结果的监测点 @@ -583,9 +583,9 @@ DAMON通过一个叫做kdamond的内核线程来进行请求监测。你可以 DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果. 当监测开启时,你可 以记录追踪点事件,并使用追踪点支持工具如perf显示结果。比如说:: - # echo on > monitor_on + # echo on > monitor_on_DEPRECATED # perf record -e damon:damon_aggregated & # sleep 5 # kill 9 $(pidof perf) - # echo off > monitor_on + # echo off > monitor_on_DEPRECATED # perf script diff --git a/Documentation/translations/zh_CN/core-api/cachetlb.rst b/Documentation/translations/zh_CN/core-api/cachetlb.rst index b4a76ec75daa..64295c61d1c1 100644 --- a/Documentation/translations/zh_CN/core-api/cachetlb.rst +++ b/Documentation/translations/zh_CN/core-api/cachetlb.rst @@ -260,7 +260,7 @@ HyperSparc cpu就是这样一个具有这种属性的cpu。 如果D-cache别名不是一个问题,这个程序可以简单地定义为该架构上 的nop。 - 在page->flags (PG_arch_1)中有一个位是“架构私有”。内核保证, + 在folio->flags (PG_arch_1)中有一个位是“架构私有”。内核保证, 对于分页缓存的页面,当这样的页面第一次进入分页缓存时,它将清除 这个位。 diff --git a/Documentation/translations/zh_CN/core-api/workqueue.rst b/Documentation/translations/zh_CN/core-api/workqueue.rst index 7fac6f75d078..fe0ff5a127f3 100644 --- a/Documentation/translations/zh_CN/core-api/workqueue.rst +++ b/Documentation/translations/zh_CN/core-api/workqueue.rst @@ -7,12 +7,13 @@ 司延腾 Yanteng Si <siyanteng@loongson.cn> 周彬彬 Binbin Zhou <zhoubinbin@loongson.cn> + 陈兴友 Xingyou Chen <rockrush@rockwork.org> .. _cn_workqueue.rst: -========================= -并发管理的工作队列 (cmwq) -========================= +======== +工作队列 +======== :日期: September, 2010 :作者: Tejun Heo <tj@kernel.org> @@ -22,7 +23,7 @@ 简介 ==== -在很多情况下,需要一个异步进程的执行环境,工作队列(wq)API是这种情况下 +在很多情况下,需要一个异步的程序执行环境,工作队列(wq)API是这种情况下 最常用的机制。 当需要这样一个异步执行上下文时,一个描述将要执行的函数的工作项(work, @@ -34,8 +35,8 @@ 队列时,工作者又开始执行。 -为什么要cmwq? -============= +为什么要有并发管理工作队列? +=========================== 在最初的wq实现中,多线程(MT)wq在每个CPU上有一个工作者线程,而单线程 (ST)wq在全系统有一个工作者线程。一个MT wq需要保持与CPU数量相同的工 @@ -73,9 +74,11 @@ 向该函数的工作项,并在工作队列中排队等待该工作项。(就是挂到workqueue 队列里面去) -特定目的线程,称为工作线程(工作者),一个接一个地执行队列中的功能。 -如果没有工作项排队,工作者线程就会闲置。这些工作者线程被管理在所谓 -的工作者池中。 +工作项可以在线程或BH(软中断)上下文中执行。 + +对于由线程执行的工作队列,被称为(内核)工作者([k]worker)的特殊 +线程会依次执行其中的函数。如果没有工作项排队,工作者线程就会闲置。 +这些工作者线程被管理在所谓的工作者池中。 cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上面排队工作, 以及管理工作者池和处理排队工作项的后端机制。 @@ -84,6 +87,10 @@ cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上 优先级的工作项,还有一些额外的工作者池,用于服务未绑定工作队列的工 作项目——这些后备池的数量是动态的。 +BH工作队列使用相同的结构。然而,由于同一时间只可能有一个执行上下文, +不需要担心并发问题。每个CPU上的BH工作者池只包含一个用于表示BH执行 +上下文的虚拟工作者。BH工作队列可以被看作软中断的便捷接口。 + 当他们认为合适的时候,子系统和驱动程序可以通过特殊的 ``workqueue API`` 函数创建和排队工作项。他们可以通过在工作队列上 设置标志来影响工作项执行方式的某些方面,他们把工作项放在那里。这些 @@ -95,9 +102,9 @@ cmwq设计区分了面向用户的工作队列,子系统和驱动程序在上 否则一个绑定的工作队列的工作项将被排在与发起线程运行的CPU相关的普 通或高级工作工作者池的工作项列表中。 -对于任何工作者池的实施,管理并发水平(有多少执行上下文处于活动状 -态)是一个重要问题。最低水平是为了节省资源,而饱和水平是指系统被 -充分使用。 +对于任何线程池的实施,管理并发水平(有多少执行上下文处于活动状 +态)是一个重要问题。cmwq试图将并发保持在一个尽可能低且充足的 +水平。最低水平是为了节省资源,而充足是为了使系统能被充分使用。 每个与实际CPU绑定的worker-pool通过钩住调度器来实现并发管理。每当 一个活动的工作者被唤醒或睡眠时,工作者池就会得到通知,并跟踪当前可 @@ -140,6 +147,17 @@ workqueue将自动创建与属性相匹配的后备工作者池。调节并发 ``flags`` --------- +``WQ_BH`` + BH工作队列可以被看作软中断的便捷接口。它总是每个CPU一份, + 其中的各个工作项也会按在队列中的顺序,被所属CPU在软中断 + 上下文中执行。 + + BH工作队列的 ``max_active`` 值必须为0,且只能单独或和 + ``WQ_HIGHPRI`` 标志组合使用。 + + BH工作项不可以睡眠。像延迟排队、冲洗、取消等所有其他特性 + 都是支持的。 + ``WQ_UNBOUND`` 排队到非绑定wq的工作项由特殊的工作者池提供服务,这些工作者不 绑定在任何特定的CPU上。这使得wq表现得像一个简单的执行环境提 @@ -184,25 +202,21 @@ workqueue将自动创建与属性相匹配的后备工作者池。调节并发 -------------- ``@max_active`` 决定了每个CPU可以分配给wq的工作项的最大执行上 -下文数量。例如,如果 ``@max_active为16`` ,每个CPU最多可以同 -时执行16个wq的工作项。 +下文数量。例如,如果 ``@max_active`` 为16 ,每个CPU最多可以同 +时执行16个wq的工作项。它总是每CPU属性,即便对于未绑定 wq。 -目前,对于一个绑定的wq, ``@max_active`` 的最大限制是512,当指 -定为0时使用的默认值是256。对于非绑定的wq,其限制是512和 -4 * ``num_possible_cpus()`` 中的较高值。这些值被选得足够高,所 -以它们不是限制性因素,同时会在失控情况下提供保护。 +``@max_active`` 的最大限制是512,当指定为0时使用的默认值是256。 +这些值被选得足够高,所以它们不是限制性因素,同时会在失控情况下提供 +保护。 一个wq的活动工作项的数量通常由wq的用户来调节,更具体地说,是由用 户在同一时间可以排列多少个工作项来调节。除非有特定的需求来控制活动 工作项的数量,否则建议指定 为"0"。 -一些用户依赖于ST wq的严格执行顺序。 ``@max_active`` 为1和 ``WQ_UNBOUND`` -的组合用来实现这种行为。这种wq上的工作项目总是被排到未绑定的工作池 -中,并且在任何时候都只有一个工作项目处于活动状态,从而实现与ST wq相 -同的排序属性。 - -在目前的实现中,上述配置只保证了特定NUMA节点内的ST行为。相反, -``alloc_ordered_workqueue()`` 应该被用来实现全系统的ST行为。 +一些用户依赖于任意时刻最多只有一个工作项被执行,且各工作项被按队列中 +顺序处理带来的严格执行顺序。``@max_active`` 为1和 ``WQ_UNBOUND`` +的组合曾被用来实现这种行为,现在不用了。请使用 +``alloc_ordered_workqueue()`` 。 执行场景示例 @@ -285,7 +299,7 @@ And with cmwq with ``@max_active`` >= 3, :: * 除非有特殊需要,建议使用0作为@max_active。在大多数使用情 况下,并发水平通常保持在默认限制之下。 -* 一个wq作为前进进度保证(WQ_MEM_RECLAIM,冲洗(flush)和工 +* 一个wq作为前进进度保证,``WQ_MEM_RECLAIM`` ,冲洗(flush)和工 作项属性的域。不涉及内存回收的工作项,不需要作为工作项组的一 部分被刷新,也不需要任何特殊属性,可以使用系统中的一个wq。使 用专用wq和系统wq在执行特性上没有区别。 @@ -294,6 +308,337 @@ And with cmwq with ``@max_active`` >= 3, :: 益的,因为wq操作和工作项执行中的定位水平提高了。 +亲和性作用域 +============ + +一个非绑定工作队列根据其亲和性作用域来对CPU进行分组以提高缓存 +局部性。比如如果一个工作队列使用默认的“cache”亲和性作用域, +它将根据最后一级缓存的边界来分组处理器。这个工作队列上的工作项 +将被分配给一个与发起CPU共用最后级缓存的处理器上的工作者。根据 +``affinity_strict`` 的设置,工作者在启动后可能被允许移出 +所在作用域,也可能不被允许。 + +工作队列目前支持以下亲和性作用域。 + +``default`` + 使用模块参数 ``workqueue.default_affinity_scope`` 指定 + 的作用域,该参数总是会被设为以下作用域中的一个。 + +``cpu`` + CPU不被分组。一个CPU上发起的工作项会被同一CPU上的工作者执行。 + 这使非绑定工作队列表现得像是不含并发管理的每CPU工作队列。 + +``smt`` + CPU被按SMT边界分组。这通常意味着每个物理CPU核上的各逻辑CPU会 + 被分进同一组。 + +``cache`` + CPU被按缓存边界分组。采用哪个缓存边界由架构代码决定。很多情况 + 下会使用L3。这是默认的亲和性作用域。 + +``numa`` + CPU被按NUMA边界分组。 + +``system`` + 所有CPU被放在同一组。工作队列不尝试在临近发起CPU的CPU上运行 + 工作项。 + +默认的亲和性作用域可以被模块参数 ``workqueue.default_affinity_scope`` +修改,特定工作队列的亲和性作用域可以通过 ``apply_workqueue_attrs()`` +被更改。 + +如果设置了 ``WQ_SYSFS`` ,工作队列会在它的 ``/sys/devices/virtual/workqueue/WQ_NAME/`` +目录中有以下亲和性作用域相关的接口文件。 + +``affinity_scope`` + 读操作以查看当前的亲和性作用域。写操作用于更改设置。 + + 当前作用域是默认值时,当前生效的作用域也可以被从这个文件中 + 读到(小括号内),例如 ``default (cache)`` 。 + +``affinity_strict`` + 默认值0表明亲和性作用域不是严格的。当一个工作项开始执行时, + 工作队列尽量尝试使工作者处于亲和性作用域内,称为遣返。启动后, + 调度器可以自由地将工作者调度到系统中任意它认为合适的地方去。 + 这使得在保留使用其他CPU(如果必需且有可用)能力的同时, + 还能从作用域局部性上获益。 + + 如果设置为1,作用域内的所有工作者将被保证总是处于作用域内。 + 这在跨亲和性作用域会导致如功耗、负载隔离等方面的潜在影响时 + 会有用。严格的NUMA作用域也可用于和旧版内核中工作队列的行为 + 保持一致。 + + +亲和性作用域与性能 +================== + +如果非绑定工作队列的行为对绝大多数使用场景来说都是最优的, +不需要更多调节,就完美了。很不幸,在当前内核中,重度使用 +工作队列时,需要在局部性和利用率间显式地作一个明显的权衡。 + +更高的局部性带来更高效率,也就是相同数量的CPU周期内可以做 +更多工作。然而,如果发起者没能将工作项充分地分散在亲和性 +作用域间,更高的局部性也可能带来更低的整体系统利用率。以下 +dm-crypt 的性能测试清楚地阐明了这一取舍。 + +测试运行在一个12核24线程、4个L3缓存的处理器(AMD Ryzen +9 3900x)上。为保持一致性,关闭CPU超频。 ``/dev/dm-0`` +是NVME SSD(三星 990 PRO)上创建,用 ``cryptsetup`` +以默认配置打开的一个 dm-crypt 设备。 + + +场景 1: 机器上遍布着有充足的发起者和工作量 +------------------------------------------ + +使用命令::: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k --ioengine=libaio \ + --iodepth=64 --runtime=60 --numjobs=24 --time_based --group_reporting \ + --name=iops-test-job --verify=sha512 + +这里有24个发起者,每个同时发起64个IO。 ``--verify=sha512`` +使得 ``fio`` 每次生成和读回内容受发起者和 ``kcryptd`` +间的执行局部性影响。下面是基于不同 ``kcryptd`` 的亲和性 +作用域设置,各经过五次测试得到的读取带宽和CPU利用率数据。 + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - 亲和性 + - 带宽 (MiBps) + - CPU利用率(%) + + * - system + - 1159.40 ±1.34 + - 99.31 ±0.02 + + * - cache + - 1166.40 ±0.89 + - 99.34 ±0.01 + + * - cache (strict) + - 1166.00 ±0.71 + - 99.35 ±0.01 + +在系统中分布着足够多发起者的情况下,不论严格与否,“cache” +没有表现得更差。三种配置均使整个机器达到饱和,但由于提高了 +局部性,缓存相关的两种有0.6%的(带宽)提升。 + + +场景 2: 更少发起者,足以达到饱和的工作量 +---------------------------------------- + +使用命令::: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ + --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=8 \ + --time_based --group_reporting --name=iops-test-job --verify=sha512 + +与上一个场景唯一的区别是 ``--numjobs=8``。 发起者数量 +减少为三分之一,但仍然有足以使系统达到饱和的工作总量。 + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - 亲和性 + - 带宽 (MiBps) + - CPU利用率(%) + + * - system + - 1155.40 ±0.89 + - 97.41 ±0.05 + + * - cache + - 1154.40 ±1.14 + - 96.15 ±0.09 + + * - cache (strict) + - 1112.00 ±4.64 + - 93.26 ±0.35 + +这里有超过使系统达到饱和所需的工作量。“system”和“cache” +都接近但并未使机器完全饱和。“cache”消耗更少的CPU但更高的 +效率使其得到和“system”相同的带宽。 + +八个发起者盘桓在四个L3缓存作用域间仍然允许“cache (strict)” +几乎使机器饱和,但缺少对工作的保持(不移到空闲处理器上) +开始带来3.7%的带宽损失。 + + +场景 3: 更少发起者,不充足的工作量 +---------------------------------- + +使用命令::: + + $ fio --filename=/dev/dm-0 --direct=1 --rw=randrw --bs=32k \ + --ioengine=libaio --iodepth=64 --runtime=60 --numjobs=4 \ + --time_based --group_reporting --name=iops-test-job --verify=sha512 + +再次,唯一的区别是 ``--numjobs=4``。由于发起者减少到四个, +现在没有足以使系统饱和的工作量,带宽变得依赖于完成时延。 + +.. list-table:: + :widths: 16 20 20 + :header-rows: 1 + + * - 亲和性 + - 带宽 (MiBps) + - CPU利用率(%) + + * - system + - 993.60 ±1.82 + - 75.49 ±0.06 + + * - cache + - 973.40 ±1.52 + - 74.90 ±0.07 + + * - cache (strict) + - 828.20 ±4.49 + - 66.84 ±0.29 + +现在,局部性和利用率间的权衡更清晰了。“cache”展示出相比 +“system”2%的带宽损失,而“cache (strict)”跌到20%。 + + +结论和建议 +---------- + +在以上试验中,虽然一致并且也明显,但“cache”亲和性作用域 +相比“system”的性能优势并不大。然而,这影响是依赖于作用域 +间距离的,在更复杂的处理器拓扑下可能有更明显的影响。 + +虽然这些情形下缺少工作保持是有坏处的,但比“cache (strict)” +好多了,而且最大化工作队列利用率的需求也并不常见。因此, +“cache”是非绑定池的默认亲和性作用域。 + +* 由于不存在一个适用于大多数场景的选择,对于可能需要消耗 + 大量CPU的工作队列,建议通过 ``apply_workqueue_attrs()`` + 进行(专门)配置,并考虑是否启用 ``WQ_SYSFS``。 + +* 设置了严格“cpu”亲和性作用域的非绑定工作队列,它的行为与 + ``WQ_CPU_INTENSIVE`` 每CPU工作队列一样。后者没有真正 + 优势,而前者提供了大幅度的灵活性。 + +* 亲和性作用域是从Linux v6.5起引入的。为了模拟旧版行为, + 可以使用严格的“numa”亲和性作用域。 + +* 不严格的亲和性作用域中,缺少工作保持大概缘于调度器。内核 + 为什么没能维护好大多数场景下的工作保持,把事情作对,还没有 + 理论上的解释。因此,未来调度器的改进可能会使我们不再需要 + 这些调节项。 + + +检查配置 +======== + +使用 tools/workqueue/wq_dump.py(drgn脚本) 来检查未 +绑定CPU的亲和性配置,工作者池,以及工作队列如何映射到池上: :: + + $ tools/workqueue/wq_dump.py + Affinity Scopes + =============== + wq_unbound_cpumask=0000000f + + CPU + nr_pods 4 + pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 + pod_node [0]=0 [1]=0 [2]=1 [3]=1 + cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 + + SMT + nr_pods 4 + pod_cpus [0]=00000001 [1]=00000002 [2]=00000004 [3]=00000008 + pod_node [0]=0 [1]=0 [2]=1 [3]=1 + cpu_pod [0]=0 [1]=1 [2]=2 [3]=3 + + CACHE (default) + nr_pods 2 + pod_cpus [0]=00000003 [1]=0000000c + pod_node [0]=0 [1]=1 + cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 + + NUMA + nr_pods 2 + pod_cpus [0]=00000003 [1]=0000000c + pod_node [0]=0 [1]=1 + cpu_pod [0]=0 [1]=0 [2]=1 [3]=1 + + SYSTEM + nr_pods 1 + pod_cpus [0]=0000000f + pod_node [0]=-1 + cpu_pod [0]=0 [1]=0 [2]=0 [3]=0 + + Worker Pools + ============ + pool[00] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 0 + pool[01] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 0 + pool[02] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 1 + pool[03] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 1 + pool[04] ref= 1 nice= 0 idle/workers= 4/ 4 cpu= 2 + pool[05] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 2 + pool[06] ref= 1 nice= 0 idle/workers= 3/ 3 cpu= 3 + pool[07] ref= 1 nice=-20 idle/workers= 2/ 2 cpu= 3 + pool[08] ref=42 nice= 0 idle/workers= 6/ 6 cpus=0000000f + pool[09] ref=28 nice= 0 idle/workers= 3/ 3 cpus=00000003 + pool[10] ref=28 nice= 0 idle/workers= 17/ 17 cpus=0000000c + pool[11] ref= 1 nice=-20 idle/workers= 1/ 1 cpus=0000000f + pool[12] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=00000003 + pool[13] ref= 2 nice=-20 idle/workers= 1/ 1 cpus=0000000c + + Workqueue CPU -> pool + ===================== + [ workqueue \ CPU 0 1 2 3 dfl] + events percpu 0 2 4 6 + events_highpri percpu 1 3 5 7 + events_long percpu 0 2 4 6 + events_unbound unbound 9 9 10 10 8 + events_freezable percpu 0 2 4 6 + events_power_efficient percpu 0 2 4 6 + events_freezable_power_ percpu 0 2 4 6 + rcu_gp percpu 0 2 4 6 + rcu_par_gp percpu 0 2 4 6 + slub_flushwq percpu 0 2 4 6 + netns ordered 8 8 8 8 8 + ... + +参见命令的帮助消息以获取更多信息。 + + +监视 +==== + +使用 tools/workqueue/wq_monitor.py 来监视工作队列的运行: :: + + $ tools/workqueue/wq_monitor.py events + total infl CPUtime CPUhog CMW/RPR mayday rescued + events 18545 0 6.1 0 5 - - + events_highpri 8 0 0.0 0 0 - - + events_long 3 0 0.0 0 0 - - + events_unbound 38306 0 0.1 - 7 - - + events_freezable 0 0 0.0 0 0 - - + events_power_efficient 29598 0 0.2 0 0 - - + events_freezable_power_ 10 0 0.0 0 0 - - + sock_diag_events 0 0 0.0 0 0 - - + + total infl CPUtime CPUhog CMW/RPR mayday rescued + events 18548 0 6.1 0 5 - - + events_highpri 8 0 0.0 0 0 - - + events_long 3 0 0.0 0 0 - - + events_unbound 38322 0 0.1 - 7 - - + events_freezable 0 0 0.0 0 0 - - + events_power_efficient 29603 0 0.2 0 0 - - + events_freezable_power_ 10 0 0.0 0 0 - - + sock_diag_events 0 0 0.0 0 0 - - + + ... + +参见命令的帮助消息以获取更多信息。 + + 调试 ==== @@ -330,7 +675,6 @@ And with cmwq with ``@max_active`` >= 3, :: 工作队列保证,如果在工作项排队后满足以下条件,则工作项不能重入: - 1. 工作函数没有被改变。 2. 没有人将该工作项排到另一个工作队列中。 3. 该工作项尚未被重新启动。 diff --git a/Documentation/translations/zh_CN/dev-tools/index.rst b/Documentation/translations/zh_CN/dev-tools/index.rst index c2db3e566b1b..fa900f5beb68 100644 --- a/Documentation/translations/zh_CN/dev-tools/index.rst +++ b/Documentation/translations/zh_CN/dev-tools/index.rst @@ -22,14 +22,14 @@ Documentation/translations/zh_CN/dev-tools/testing-overview.rst sparse gcov kasan + kcov + ubsan + kmemleak gdb-kernel-debugging Todolist: - coccinelle - - kcov - - ubsan - - kmemleak - kcsan - kfence - kgdb diff --git a/Documentation/translations/zh_CN/dev-tools/kasan.rst b/Documentation/translations/zh_CN/dev-tools/kasan.rst index 8fdb20c9665b..2b1e8f74904b 100644 --- a/Documentation/translations/zh_CN/dev-tools/kasan.rst +++ b/Documentation/translations/zh_CN/dev-tools/kasan.rst @@ -137,7 +137,7 @@ KASAN受到通用 ``panic_on_warn`` 命令行参数的影响。当它被启用 典型的KASAN报告如下所示:: ================================================================== - BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [test_kasan] + BUG: KASAN: slab-out-of-bounds in kmalloc_oob_right+0xa8/0xbc [kasan_test] Write of size 1 at addr ffff8801f44ec37b by task insmod/2760 CPU: 1 PID: 2760 Comm: insmod Not tainted 4.19.0-rc3+ #698 @@ -147,8 +147,8 @@ KASAN受到通用 ``panic_on_warn`` 命令行参数的影响。当它被启用 print_address_description+0x73/0x280 kasan_report+0x144/0x187 __asan_report_store1_noabort+0x17/0x20 - kmalloc_oob_right+0xa8/0xbc [test_kasan] - kmalloc_tests_init+0x16/0x700 [test_kasan] + kmalloc_oob_right+0xa8/0xbc [kasan_test] + kmalloc_tests_init+0x16/0x700 [kasan_test] do_one_initcall+0xa5/0x3ae do_init_module+0x1b6/0x547 load_module+0x75df/0x8070 @@ -168,8 +168,8 @@ KASAN受到通用 ``panic_on_warn`` 命令行参数的影响。当它被启用 save_stack+0x43/0xd0 kasan_kmalloc+0xa7/0xd0 kmem_cache_alloc_trace+0xe1/0x1b0 - kmalloc_oob_right+0x56/0xbc [test_kasan] - kmalloc_tests_init+0x16/0x700 [test_kasan] + kmalloc_oob_right+0x56/0xbc [kasan_test] + kmalloc_tests_init+0x16/0x700 [kasan_test] do_one_initcall+0xa5/0x3ae do_init_module+0x1b6/0x547 load_module+0x75df/0x8070 @@ -421,15 +421,15 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。 当由于 ``kmalloc`` 失败而导致测试失败时:: - # kmalloc_large_oob_right: ASSERTION FAILED at lib/test_kasan.c:163 + # kmalloc_large_oob_right: ASSERTION FAILED at mm/kasan/kasan_test.c:245 Expected ptr is not null, but is - not ok 4 - kmalloc_large_oob_right + not ok 5 - kmalloc_large_oob_right 当由于缺少KASAN报告而导致测试失败时:: - # kmalloc_double_kzfree: EXPECTATION FAILED at lib/test_kasan.c:974 + # kmalloc_double_kzfree: EXPECTATION FAILED at mm/kasan/kasan_test.c:709 KASAN failure expected in "kfree_sensitive(ptr)", but none occurred - not ok 44 - kmalloc_double_kzfree + not ok 28 - kmalloc_double_kzfree 最后打印所有KASAN测试的累积状态。成功:: @@ -445,7 +445,7 @@ KASAN连接到vmap基础架构以懒清理未使用的影子内存。 1. 可加载模块 启用 ``CONFIG_KUNIT`` 后,KASAN-KUnit测试可以构建为可加载模块,并通过使用 - ``insmod`` 或 ``modprobe`` 加载 ``test_kasan.ko`` 来运行。 + ``insmod`` 或 ``modprobe`` 加载 ``kasan_test.ko`` 来运行。 2. 内置 diff --git a/Documentation/translations/zh_CN/dev-tools/kcov.rst b/Documentation/translations/zh_CN/dev-tools/kcov.rst new file mode 100644 index 000000000000..629154df7121 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/kcov.rst @@ -0,0 +1,359 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/kcov.rst +:Translator: 刘浩阳 Haoyang Liu <tttturtleruss@hust.edu.cn> + +KCOV: 用于模糊测试的代码覆盖率 +============================== + +KCOV 以一种适用于覆盖率引导的模糊测试的形式收集和暴露内核代码覆盖率信息。 +一个正在运行的内核的覆盖率数据可以通过 ``kcov`` 调试文件导出。覆盖率的收集是基 +于任务启用的,因此 KCOV 可以精确捕获单个系统调用的覆盖率。 + +要注意的是 KCOV 不是为了收集尽可能多的覆盖率数据。而是为了收集相对稳定的覆盖率 +,这是系统调用输入的函数。为了完成这个目标,它不收集软硬中断的覆盖率(除非移除 +覆盖率收集被启用,见下文)以及内核中固有的不确定部分的覆盖率(如调度器,锁定) + +除了收集代码覆盖率,KCOV 还收集操作数比较的覆盖率。见 "操作数比较收集" 一节 +查看详细信息。 + +除了从系统调用处理器收集覆盖率数据,KCOV 还从后台内核或软中断任务中执行的内核 +被标注的部分收集覆盖率。见 "远程覆盖率收集" 一节查看详细信息。 + +先决条件 +-------- + +KCOV 依赖编译器插桩,要求 GCC 6.1.0 及更高版本或者内核支持的任意版本的 Clang。 + +收集操作数比较的覆盖率需要 GCC 8+ 或者 Clang。 + +为了启用 KCOV,需要使用如下参数配置内核:: + + CONFIG_KCOV=y + +为了启用操作数比较覆盖率的收集,使用如下参数:: + + CONFIG_KCOV_ENABLE_COMPARISONS=y + +覆盖率数据只会在调试文件系统被挂载后才可以获取:: + + mount -t debugfs none /sys/kernel/debug + +覆盖率收集 +---------- + +下面的程序演示了如何使用 KCOV 在一个测试程序中收集单个系统调用的覆盖率: + +.. code-block:: c + + #include <stdio.h> + #include <stddef.h> + #include <stdint.h> + #include <stdlib.h> + #include <sys/types.h> + #include <sys/stat.h> + #include <sys/ioctl.h> + #include <sys/mman.h> + #include <unistd.h> + #include <fcntl.h> + #include <linux/types.h> + + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) + #define KCOV_ENABLE _IO('c', 100) + #define KCOV_DISABLE _IO('c', 101) + #define COVER_SIZE (64<<10) + + #define KCOV_TRACE_PC 0 + #define KCOV_TRACE_CMP 1 + + int main(int argc, char **argv) + { + int fd; + unsigned long *cover, n, i; + + /* 单个文件描述符允许 + * 在单线程上收集覆盖率。 + */ + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + /* 设置跟踪模式和跟踪大小。 */ + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + /* 映射内核空间和用户空间共享的缓冲区。 */ + cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + /* 在当前线程中启用覆盖率收集。 */ + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_PC)) + perror("ioctl"), exit(1); + /* 在调用 ioctl() 之后重置覆盖率。 */ + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + /* 调用目标系统调用。 */ + read(-1, NULL, 0); + /* 读取收集到的 PC 的数目。 */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) + printf("0x%lx\n", cover[i + 1]); + /* 在当前线程上禁用覆盖率收集。在这之后 + * 可以在其他线程上收集覆盖率 + */ + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + /* 释放资源 */ + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } + +在使用 ``addr2line`` 传输后,程序输出应该如下所示:: + + SyS_read + fs/read_write.c:562 + __fdget_pos + fs/file.c:774 + __fget_light + fs/file.c:746 + __fget_light + fs/file.c:750 + __fget_light + fs/file.c:760 + __fdget_pos + fs/file.c:784 + SyS_read + fs/read_write.c:562 + +如果一个程序需要从多个线程收集覆盖率(独立地)。那么每个线程都需要单独打开 +``/sys/kernel/debug/kcov``。 + +接口的细粒度允许高效的创建测试进程。即,一个父进程打开了 +``/sys/kernel/debug/kcov``,启用了追踪模式,映射了覆盖率缓冲区,然后在一个循 +环中创建了子进程。这个子进程只需要启用覆盖率收集即可(当一个线程退出时将自动禁 +用覆盖率收集)。 + +操作数比较收集 +-------------- + +操作数比较收集和覆盖率收集类似: + +.. code-block:: c + + /* 包含和上文一样的头文件和宏定义。 */ + + /* 每次记录的 64 位字的数量。 */ + #define KCOV_WORDS_PER_CMP 4 + + /* + * 收集的比较种类的格式。 + * + * 0 比特表示是否是一个编译时常量。 + * 1 & 2 比特包含参数大小的 log2 值,最大 8 字节。 + */ + + #define KCOV_CMP_CONST (1 << 0) + #define KCOV_CMP_SIZE(n) ((n) << 1) + #define KCOV_CMP_MASK KCOV_CMP_SIZE(3) + + int main(int argc, char **argv) + { + int fd; + uint64_t *cover, type, arg1, arg2, is_const, size; + unsigned long n, i; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + /* + * 注意缓冲区指针的类型是 uint64_t*,因为所有的 + * 比较操作数都被提升为 uint64_t 类型。 + */ + cover = (uint64_t *)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + /* 注意这里是 KCOV_TRACE_CMP 而不是 KCOV_TRACE_PC。 */ + if (ioctl(fd, KCOV_ENABLE, KCOV_TRACE_CMP)) + perror("ioctl"), exit(1); + __atomic_store_n(&cover[0], 0, __ATOMIC_RELAXED); + read(-1, NULL, 0); + /* 读取收集到的比较操作数的数量。 */ + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) { + uint64_t ip; + + type = cover[i * KCOV_WORDS_PER_CMP + 1]; + /* arg1 和 arg2 - 比较的两个操作数。 */ + arg1 = cover[i * KCOV_WORDS_PER_CMP + 2]; + arg2 = cover[i * KCOV_WORDS_PER_CMP + 3]; + /* ip - 调用者的地址。 */ + ip = cover[i * KCOV_WORDS_PER_CMP + 4]; + /* 操作数的大小。 */ + size = 1 << ((type & KCOV_CMP_MASK) >> 1); + /* is_const - 当操作数是一个编译时常量时为真。*/ + is_const = type & KCOV_CMP_CONST; + printf("ip: 0x%lx type: 0x%lx, arg1: 0x%lx, arg2: 0x%lx, " + "size: %lu, %s\n", + ip, type, arg1, arg2, size, + is_const ? "const" : "non-const"); + } + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + /* 释放资源。 */ + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } + +注意 KCOV 的模式(代码覆盖率收集或操作数比较收集)是互斥的。 + +远程覆盖率收集 +-------------- + +除了从用户空间进程发布的系统调用句柄收集覆盖率数据以外,KCOV 也可以从部分在其 +他上下文中执行的内核中收集覆盖率 - 称为“远程”覆盖率。 + +使用 KCOV 收集远程覆盖率要求: + +1. 修改内核源码并使用 ``kcov_remote_start`` 和 ``kcov_remote_stop`` 来标注要收集 + 覆盖率的代码片段。 + +2. 在用户空间的收集覆盖率的进程应使用 ``KCOV_REMOTE_ENABLE`` 而不是 ``KCOV_ENABLE``。 + +``kcov_remote_start`` 和 ``kcov_remote_stop`` 的标注以及 ``KCOV_REMOTE_ENABLE`` +ioctl 都接受可以识别特定覆盖率收集片段的句柄。句柄的使用方式取决于匹配代码片段执 +行的上下文。 + +KCOV 支持在如下上下文中收集远程覆盖率: + +1. 全局内核后台任务。这些任务是内核启动时创建的数量有限的实例(如,每一个 + USB HCD 产生一个 USB ``hub_event`` 工作器)。 + +2. 局部内核后台任务。这些任务通常是由于用户空间进程与某些内核接口进行交互时产 + 生的,并且通常在进程退出时会被停止(如,vhost 工作器)。 + +3. 软中断。 + +对于 #1 和 #3,必须选择一个独特的全局句柄并将其传递给对应的 +``kcov_remote_start`` 调用。一个用户空间进程必须将该句柄存储在 +``kcov_remote_arg`` 结构体的 ``handle`` 数组字段中并将其传递给 +``KCOV_REMOTE_ENABLE``。这会将使用的 KCOV 设备附加到由此句柄引用的代码片段。多个全局 +句柄标识的不同代码片段可以一次性传递。 + +对于 #2,用户空间进程必须通过 ``kcov_remote_arg`` 结构体的 ``common_handle`` 字段 +传递一个非零句柄。这个通用句柄将会被保存在当前 ``task_struct`` 结构体的 +``kcov_handle`` 字段中并且需要通过自定义内核代码的修改来传递给新创建的本地任务 +。这些任务需要在 ``kcov_remote_start`` 和 ``kcov_remote_stop`` 标注中依次使用传递过来的 +句柄。 + +KCOV 对全局句柄和通用句柄均遵循一个预定义的格式。每一个句柄都是一个 ``u64`` 整形 +。当前,只有最高位和低四位字节被使用。第 4-7 字节是保留位并且值必须为 0。 + +对于全局句柄,最高位的字节表示该句柄属于的子系统的标识。比如,KCOV 使用 ``1`` +表示 USB 子系统类型。全局句柄的低 4 字节表示子系统中任务实例的标识。比如,每一 +个 ``hub_event`` 工作器使用 USB 总线号作为任务实例的标识。 + +对于通用句柄,使用一个保留值 ``0`` 作为子系统标识,因为这些句柄不属于一个特定 +的子系统。通用句柄的低 4 字节用于识别有用户进程生成的所有本地句柄的集合实例, +该进程将通用句柄传递给 ``KCOV_REMOTE_ENABLE``。 + +实际上,如果只从系统中的单个用户空间进程收集覆盖率,那么可以使用任意值作为通用 +句柄的实例标识。然而,如果通用句柄被多个用户空间进程使用,每个进程必须使用唯一 +的实例标识。一个选择是使用进程标识作为通用句柄实例的标识。 + +下面的程序演示了如何使用 KCOV 从一个由进程产生的本地任务和处理 USB 总线的全局 +任务 #1 收集覆盖率: + +.. code-block:: c + + /* 包含和上文一样的头文件和宏定义。 */ + + struct kcov_remote_arg { + __u32 trace_mode; + __u32 area_size; + __u32 num_handles; + __aligned_u64 common_handle; + __aligned_u64 handles[0]; + }; + + #define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) + #define KCOV_DISABLE _IO('c', 101) + #define KCOV_REMOTE_ENABLE _IOW('c', 102, struct kcov_remote_arg) + + #define COVER_SIZE (64 << 10) + + #define KCOV_TRACE_PC 0 + + #define KCOV_SUBSYSTEM_COMMON (0x00ull << 56) + #define KCOV_SUBSYSTEM_USB (0x01ull << 56) + + #define KCOV_SUBSYSTEM_MASK (0xffull << 56) + #define KCOV_INSTANCE_MASK (0xffffffffull) + + static inline __u64 kcov_remote_handle(__u64 subsys, __u64 inst) + { + if (subsys & ~KCOV_SUBSYSTEM_MASK || inst & ~KCOV_INSTANCE_MASK) + return 0; + return subsys | inst; + } + + #define KCOV_COMMON_ID 0x42 + #define KCOV_USB_BUS_NUM 1 + + int main(int argc, char **argv) + { + int fd; + unsigned long *cover, n, i; + struct kcov_remote_arg *arg; + + fd = open("/sys/kernel/debug/kcov", O_RDWR); + if (fd == -1) + perror("open"), exit(1); + if (ioctl(fd, KCOV_INIT_TRACE, COVER_SIZE)) + perror("ioctl"), exit(1); + cover = (unsigned long*)mmap(NULL, COVER_SIZE * sizeof(unsigned long), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if ((void*)cover == MAP_FAILED) + perror("mmap"), exit(1); + + /* 通过通用句柄和 USB 总线 #1 启用代码覆盖率收集。 */ + arg = calloc(1, sizeof(*arg) + sizeof(uint64_t)); + if (!arg) + perror("calloc"), exit(1); + arg->trace_mode = KCOV_TRACE_PC; + arg->area_size = COVER_SIZE; + arg->num_handles = 1; + arg->common_handle = kcov_remote_handle(KCOV_SUBSYSTEM_COMMON, + KCOV_COMMON_ID); + arg->handles[0] = kcov_remote_handle(KCOV_SUBSYSTEM_USB, + KCOV_USB_BUS_NUM); + if (ioctl(fd, KCOV_REMOTE_ENABLE, arg)) + perror("ioctl"), free(arg), exit(1); + free(arg); + + /* + * 在这里用户需要触发执行一个内核代码段 + * 该代码段要么使用通用句柄标识 + * 要么触发了一些 USB 总线 #1 上的一些活动。 + */ + sleep(2); + + n = __atomic_load_n(&cover[0], __ATOMIC_RELAXED); + for (i = 0; i < n; i++) + printf("0x%lx\n", cover[i + 1]); + if (ioctl(fd, KCOV_DISABLE, 0)) + perror("ioctl"), exit(1); + if (munmap(cover, COVER_SIZE * sizeof(unsigned long))) + perror("munmap"), exit(1); + if (close(fd)) + perror("close"), exit(1); + return 0; + } diff --git a/Documentation/translations/zh_CN/dev-tools/kmemleak.rst b/Documentation/translations/zh_CN/dev-tools/kmemleak.rst new file mode 100644 index 000000000000..d248c8428095 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/kmemleak.rst @@ -0,0 +1,229 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/kmemleak.rst +:Translator: 刘浩阳 Haoyang Liu <tttturtleruss@hust.edu.cn> + +内核内存泄露检测器 +================== + +Kmemleak 提供了一个类似 `可追踪的垃圾收集器 <https://en.wikipedia.org/wiki/Tra +cing_garbage_collection>`_ 的方法来检测可能的内核内存泄漏,不同的是孤立对象不会 +被释放,而是仅通过 /sys/kernel/debug/kmemleak 报告。Valgrind 工具 +(``memcheck --leak-check``)使用了一种相似的方法来检测用户空间应用中的内存泄 +露。 + +用法 +---- + +"Kernel hacking" 中的 CONFIG_DEBUG_KMEMLEAK 必须被启用。一个内核线程每10分钟 +(默认情况下)扫描一次内存,并且打印出新发现的未被引用的对象个数。 +如果 ``debugfs`` 没有挂载,则执行:: + + # mount -t debugfs nodev /sys/kernel/debug/ + +显示所有扫描出的可能的内存泄漏的细节信息:: + + # cat /sys/kernel/debug/kmemleak + +启动一次中等程度的内存扫描:: + + # echo scan > /sys/kernel/debug/kmemleak + +清空当前所有可能的内存泄露列表:: + + # echo clear > /sys/kernel/debug/kmemleak + +当再次读取 ``/sys/kernel/debug/kmemleak`` 文件时,将会输出自上次扫描以来检测到的 +新的内存泄露。 + +注意,孤立目标是通过被分配时间来排序的,列表开始的对象可能会导致后续的对象都被 +识别为孤立对象。 + +可以通过写入 ``/sys/kernel/debug/kmemleak`` 文件在运行时修改内存扫描参数。下面是 +支持的参数: + + +* off + 禁用 kmemleak(不可逆) +* stack=on + 开启任务栈扫描(默认) +* stack=off + 禁用任务栈扫描 +* scan=on + 开启自动内存扫描线程(默认) +* scan=off + 关闭自动内存扫描线程 +* scan=<secs>; + 设定自动内存扫描间隔,以秒为单位(默认值为 600,设置为 0 表示停 + 止自动扫描) +* scan + 触发一次内存扫描 +* clear + 通过标记所有当前已报告的未被引用对象为灰,从而清空当前可能的内存泄露列 + 表;如果 kmemleak 被禁用,则释放所有 kmemleak 对象,。 +* dump=<addr> + 输出存储在 <addr> 中的对象信息 + +可以通过在内核命令行中传递 ``kmemleak=off`` 参数从而在启动时禁用 Kmemleak。 + +在 kmemleak 初始化之前就可能会有内存分配或释放,这些操作被存储在一个早期日志缓 +冲区中。缓冲区的大小通过 CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE 选项配置。 + +如果 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF 被启用,则 kmemleak 默认被禁用。在内核命 +令行中传递 ``kmemleak=on`` 参数来开启这个功能。 + +如果出现 "Error while writing to stdout" 或 "write_loop: Invalid argument" 这样 +的错误,请确认 kmemleak 被正确启用。 + +基础算法 +-------- + +通过 :c:func:`kmalloc`, :c:func:`vmalloc`, :c:func:`kmem_cache_alloc` 以及同类 +函数均被跟踪,指针,包括一些额外的信息如大小和栈追踪等,都被存储在红黑树中。 +对应的释放函数调用也被追踪,并从 kmemleak 数据结构中移除相应指针。 + +对于一个已分配的内存块,如果通过扫描内存(包括保存寄存器)没有发现任何指针指向 +它的起始地址或者其中的任何位置,则认为这块内存是孤立的。这意味着内核无法将该内 +存块的地址传递给一个释放内存函数,这块内存便被认为泄露了。 + +扫描算法步骤: + + 1. 标记所有对象为白色(最后剩下的白色对象被认为是孤立的) + 2. 从数据节和栈开始扫描内存,检测每个值是否是红黑树中存储的地址。如果一个指向 + 白色对象的指针被检测到,则将该对象标记为灰色。 + 3. 扫描灰色对象引用的其他对象(有些白色对象可能会变为灰色并被添加到灰名单末尾 + )直到灰名单为空。 + 4. 剩余的白色对象就被认为是孤立的并通过 /sys/kernel/debug/kmemleak 报告。 + +有些指向已分配的内存块的指针存储在内核内部的数据结构中,它们不能被检测为孤立。 +为了避免这种情况,kmemleak 也存储了指向需要被查找的内存块范围内的任意地址的地址 +数量,如此一来这些内存便不会被认为泄露。一个例子是 __vmalloc()。 + +用 kmemleak 测试特定部分 +------------------------ + +在初始化启动阶段 /sys/kernel/debug/kmemleak 的输出可能会很多,这也可能是你在开发 +时编写的漏洞百出的代码导致的。为了解决这种情况你可以使用 'clear' 命令来清除 +/sys/kernel/debug/kmemleak 输出的所有的未引用对象。在执行 'clear' 后执行 'scan' +可以发现新的未引用对象,这将会有利你测试代码的特定部分。 + +为了用一个空的 kmemleak 测试一个特定部分,执行:: + + # echo clear > /sys/kernel/debug/kmemleak + ... 测试你的内核或者模块 ... + # echo scan > /sys/kernel/debug/kmemleak + +然后像平常一样获得报告:: + + # cat /sys/kernel/debug/kmemleak + +释放 kmemleak 内核对象 +---------------------- + +为了允许访问先前发现的内存泄露,当用户禁用或发生致命错误导致 kmemleak +被禁用时,内核中的 kmemleak 对象不会被释放。这些对象可能会占用很大 +一部分物理内存。 + +在这种情况下,你可以用如下命令回收这些内存:: + + # echo clear > /sys/kernel/debug/kmemleak + +Kmemleak API +------------ + +在 include/linux/kmemleak.h 头文件中查看函数原型: + +- ``kmemleak_init`` - 初始化 kmemleak +- ``kmemleak_alloc`` - 通知一个内存块的分配 +- ``kmemleak_alloc_percpu`` - 通知一个 percpu 类型的内存分配 +- ``kmemleak_vmalloc`` - 通知一个使用 vmalloc() 的内存分配 +- ``kmemleak_free`` - 通知一个内存块的释放 +- ``kmemleak_free_part`` - 通知一个部分的内存释放 +- ``kmemleak_free_percpu`` - 通知一个 percpu 类型的内存释放 +- ``kmemleak_update_trace`` - 更新分配对象过程的栈追踪 +- ``kmemleak_not_leak`` - 标记一个对象内存为未泄露的 +- ``kmemleak_ignore`` - 不要扫描或报告某个对象未泄露的 +- ``kmemleak_scan_area`` - 在内存块中添加扫描区域 +- ``kmemleak_no_scan`` - 不扫描某个内存块 +- ``kmemleak_erase`` - 在指针变量中移除某个旧的值 +- ``kmemleak_alloc_recursive`` - 和 kmemleak_alloc 效果相同但会检查是否有递归的 + 内存分配 +- ``kmemleak_free_recursive`` - 和 kmemleak_free 效果相同但会检查是否有递归的 + 内存释放 + +下列函数使用一个物理地址作为对象指针并且只在地址有一个 lowmem 映射时做出相应的 +行为: + +- ``kmemleak_alloc_phys`` +- ``kmemleak_free_part_phys`` +- ``kmemleak_ignore_phys`` + +解决假阳性/假阴性 +----------------- + +假阴性是指由于在内存扫描中有值指向该对象导致 kmemleak 没有报告的实际存在的内存 +泄露(孤立对象)。为了减少假阴性的出现次数,kmemleak 提供了 kmemleak_ignore, +kmemleak_scan_area,kmemleak_no_scan 和 kmemleak_erase 函数(见上)。 +任务栈也会增加假阴性的数量并且默认不开启对它们的扫描。 + +假阳性是对象被误报为内存泄露(孤立对象)。对于已知未泄露的对象,kmemleak +提供了 kmemleak_not_leak 函数。同时 kmemleak_ignore 可以用于标记已知不包含任何 +其他指针的内存块,标记后该内存块不会再被扫描。 + +一些被报告的泄露仅仅是暂时的,尤其是在 SMP(对称多处理)系统中,因为其指针 +暂存在 CPU 寄存器或栈中。Kmemleak 定义了 MSECS_MIN_AGE(默认值为 1000) +来表示一个被报告为内存泄露的对象的最小存活时间。 + +限制和缺点 +---------- + +主要的缺点是内存分配和释放的性能下降。为了避免其他的损失,只有当 +/sys/kernel/debug/kmemleak 文件被读取时才会进行内存扫描。无论如何,这个工具是出于 +调试的目标,性能表现可能不是最重要的。 + +为了保持算法简单,kmemleak 寻找指向某个内存块范围中的任何值。这可能会引发假阴性 +现象的出现。但是,最后一个真正的内存泄露也会变得明显。 + +非指针值的数据是假阴性的另一个来源。在将来的版本中,kmemleak 仅仅会扫 +描已分配结构体中的指针成员。这个特性会解决上述很多的假阴性情况。 + +Kmemleak 会报告假阳性。这可能发生在某些被分配的内存块不需要被释放的情况下 +(某些 init_call 函数中),指针的计算是通过其他方法而不是常规的 container_of 宏 +或是指针被存储在 kmemleak 没有扫描的地方。 + +页分配和 ioremap 不会被追踪。 + +使用 kmemleak-test 测试 +----------------------- + +为了检测是否成功启用了 kmemleak,你可以使用一个故意制造内存泄露的模块 +kmemleak-test。设置 CONFIG_SAMPLE_KMEMLEAK 为模块(不能作为内建模块使用) +并且启动启用了 kmemleak 的内核。加载模块并执行一次扫描:: + + # modprobe kmemleak-test + # echo scan > /sys/kernel/debug/kmemleak + +注意你可能无法立刻或在第一次扫描后得到结果。当 kmemleak 得到结果,将会输出日 +志 ``kmemleak: <count of leaks> new suspected memory leaks`` 。然后通过读取文件 +获取信息:: + + # cat /sys/kernel/debug/kmemleak + unreferenced object 0xffff89862ca702e8 (size 32): + comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s) + hex dump (first 32 bytes): + 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk + 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. + backtrace: + [<00000000e0a73ec7>] 0xffffffffc01d2036 + [<000000000c5d2a46>] do_one_initcall+0x41/0x1df + [<0000000046db7e0a>] do_init_module+0x55/0x200 + [<00000000542b9814>] load_module+0x203c/0x2480 + [<00000000c2850256>] __do_sys_finit_module+0xba/0xe0 + [<000000006564e7ef>] do_syscall_64+0x43/0x110 + [<000000007c873fa6>] entry_SYSCALL_64_after_hwframe+0x44/0xa9 + ... + +用 ``rmmod kmemleak_test`` 移除模块时也会触发 +kmemleak 的结果输出。 diff --git a/Documentation/translations/zh_CN/dev-tools/ubsan.rst b/Documentation/translations/zh_CN/dev-tools/ubsan.rst new file mode 100644 index 000000000000..2487696b3772 --- /dev/null +++ b/Documentation/translations/zh_CN/dev-tools/ubsan.rst @@ -0,0 +1,91 @@ +.. SPDX-License-Identifier: GPL-2.0 + +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/dev-tools/ubsan.rst +:Translator: Dongliang Mu <dzm91@hust.edu.cn> + +未定义行为消毒剂 - UBSAN +==================================== + +UBSAN是一种动态未定义行为检查工具。 + +UBSAN使用编译时插桩捕捉未定义行为。编译器在可能导致未定义行为的操作前插入特定 +检测代码。如果检查失败,即检测到未定义行为,__ubsan_handle_* 函数将被调用打印 +错误信息。 + +GCC自4.9.x [1_] (详见 ``-fsanitize=undefined`` 选项及其子选项)版本后引入这 +一特性。GCC 5.x 版本实现了更多检查器 [2_]。 + +报告样例 +-------------- + +:: + + ================================================================================ + UBSAN: Undefined behaviour in ../include/linux/bitops.h:110:33 + shift exponent 32 is to large for 32-bit type 'unsigned int' + CPU: 0 PID: 0 Comm: swapper Not tainted 4.4.0-rc1+ #26 + 0000000000000000 ffffffff82403cc8 ffffffff815e6cd6 0000000000000001 + ffffffff82403cf8 ffffffff82403ce0 ffffffff8163a5ed 0000000000000020 + ffffffff82403d78 ffffffff8163ac2b ffffffff815f0001 0000000000000002 + Call Trace: + [<ffffffff815e6cd6>] dump_stack+0x45/0x5f + [<ffffffff8163a5ed>] ubsan_epilogue+0xd/0x40 + [<ffffffff8163ac2b>] __ubsan_handle_shift_out_of_bounds+0xeb/0x130 + [<ffffffff815f0001>] ? radix_tree_gang_lookup_slot+0x51/0x150 + [<ffffffff8173c586>] _mix_pool_bytes+0x1e6/0x480 + [<ffffffff83105653>] ? dmi_walk_early+0x48/0x5c + [<ffffffff8173c881>] add_device_randomness+0x61/0x130 + [<ffffffff83105b35>] ? dmi_save_one_device+0xaa/0xaa + [<ffffffff83105653>] dmi_walk_early+0x48/0x5c + [<ffffffff831066ae>] dmi_scan_machine+0x278/0x4b4 + [<ffffffff8111d58a>] ? vprintk_default+0x1a/0x20 + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 + [<ffffffff830b2240>] setup_arch+0x405/0xc2c + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 + [<ffffffff830ae053>] start_kernel+0x83/0x49a + [<ffffffff830ad120>] ? early_idt_handler_array+0x120/0x120 + [<ffffffff830ad386>] x86_64_start_reservations+0x2a/0x2c + [<ffffffff830ad4f3>] x86_64_start_kernel+0x16b/0x17a + ================================================================================ + +用法 +----- + +使用如下内核配置启用UBSAN:: + + CONFIG_UBSAN=y + +使用如下内核配置检查整个内核:: + + CONFIG_UBSAN_SANITIZE_ALL=y + +为了在特定文件或目录启动代码插桩,需要在相应的内核Makefile中添加一行类似内容: + +- 单文件(如main.o):: + + UBSAN_SANITIZE_main.o := y + +- 一个目录中的所有文件:: + + UBSAN_SANITIZE := y + +即使设置了``CONFIG_UBSAN_SANITIZE_ALL=y``,为了避免文件被插桩,可使用:: + + UBSAN_SANITIZE_main.o := n + +与:: + + UBSAN_SANITIZE := n + +未对齐的内存访问检测可通过开启独立选项 - CONFIG_UBSAN_ALIGNMENT 检测。 +该选项在支持未对齐访问的架构上(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y) +默认为关闭。该选项仍可通过内核配置启用,但它将产生大量的UBSAN报告。 + +参考文献 +---------- + +.. _1: https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gcc/Debugging-Options.html +.. _2: https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html +.. _3: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html diff --git a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst index aeccff777170..0faf042001d2 100644 --- a/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst +++ b/Documentation/translations/zh_CN/driver-api/gpio/legacy.rst @@ -208,8 +208,6 @@ GPIO 值的命令需要等待其信息排到队首才发送命令,再获得其 gpio_request() ## gpio_request_one() - ## gpio_request_array() - ## gpio_free_array() gpio_free() @@ -272,14 +270,6 @@ gpio_request()前将这类细节配置好,例如使用引脚控制子系统的 */ int gpio_request_one(unsigned gpio, unsigned long flags, const char *label); - /* 在单个函数中申请多个 GPIO - */ - int gpio_request_array(struct gpio *array, size_t num); - - /* 在单个函数中释放多个 GPIO - */ - void gpio_free_array(struct gpio *array, size_t num); - 这里 'flags' 当前定义可指定以下属性: * GPIOF_DIR_IN - 配置方向为输入 @@ -317,12 +307,6 @@ gpio_request()前将这类细节配置好,例如使用引脚控制子系统的 if (err) ... - err = gpio_request_array(leds_gpios, ARRAY_SIZE(leds_gpios)); - if (err) - ... - - gpio_free_array(leds_gpios, ARRAY_SIZE(leds_gpios)); - GPIO 映射到 IRQ ---------------- diff --git a/Documentation/translations/zh_CN/index.rst b/Documentation/translations/zh_CN/index.rst index 6ccec9657cc6..20b9d4270d1f 100644 --- a/Documentation/translations/zh_CN/index.rst +++ b/Documentation/translations/zh_CN/index.rst @@ -24,8 +24,8 @@ 上的linux-doc邮件列表。 顺便说下,中文文档也需要遵守内核编码风格,风格中中文和英文的主要不同就是中文 -的字符标点占用两个英文字符宽度, 所以,当英文要求不要超过每行100个字符时, -中文就不要超过50个字符。另外,也要注意'-','=' 等符号与相关标题的对齐。在将 +的字符标点占用两个英文字符宽度,所以,当英文要求不要超过每行100个字符时, +中文就不要超过50个字符。另外,也要注意'-','='等符号与相关标题的对齐。在将 补丁提交到社区之前,一定要进行必要的 ``checkpatch.pl`` 检查和编译测试。 与Linux 内核社区一起工作 diff --git a/Documentation/translations/zh_CN/mm/page_frags.rst b/Documentation/translations/zh_CN/mm/page_frags.rst index 20bd3fafdc8c..a5b22486a913 100644 --- a/Documentation/translations/zh_CN/mm/page_frags.rst +++ b/Documentation/translations/zh_CN/mm/page_frags.rst @@ -25,7 +25,7 @@ sk_buff->head使用,或者用于skb_shared_info的 “frags” 部分。 网络堆栈在每个CPU使用两个独立的缓存来处理碎片分配。netdev_alloc_cache被使用 netdev_alloc_frag和__netdev_alloc_skb调用的调用者使用。napi_alloc_cache -被调用__napi_alloc_frag和__napi_alloc_skb的调用者使用。这两个调用的主要区别是 +被调用__napi_alloc_frag和napi_alloc_skb的调用者使用。这两个调用的主要区别是 它们可能被调用的环境。“netdev” 前缀的函数可以在任何上下文中使用,因为这些函数 将禁用中断,而 ”napi“ 前缀的函数只可以在softirq上下文中使用。 diff --git a/Documentation/translations/zh_CN/power/opp.rst b/Documentation/translations/zh_CN/power/opp.rst index 8d6e3f6f6202..7470fa2d4c43 100644 --- a/Documentation/translations/zh_CN/power/opp.rst +++ b/Documentation/translations/zh_CN/power/opp.rst @@ -274,7 +274,7 @@ dev_pm_opp_get_opp_count { /* 做一些事情 */ num_available = dev_pm_opp_get_opp_count(dev); - speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL); + speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL); /* 按升序填充表 */ freq = 0; while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) { diff --git a/Documentation/translations/zh_CN/process/coding-style.rst b/Documentation/translations/zh_CN/process/coding-style.rst index fa28ef0a7fee..3bc2810b151d 100644 --- a/Documentation/translations/zh_CN/process/coding-style.rst +++ b/Documentation/translations/zh_CN/process/coding-style.rst @@ -523,9 +523,9 @@ Linux 里这是提倡的做法,因为这样可以很简单的给读者提供 .. code-block:: c - err_free_bar: + err_free_bar: kfree(foo->bar); - err_free_foo: + err_free_foo: kfree(foo); return ret; diff --git a/Documentation/translations/zh_CN/process/cve.rst b/Documentation/translations/zh_CN/process/cve.rst new file mode 100644 index 000000000000..e39b796efcec --- /dev/null +++ b/Documentation/translations/zh_CN/process/cve.rst @@ -0,0 +1,89 @@ +.. include:: ../disclaimer-zh_CN.rst + +:Original: Documentation/process/cve.rst +:Translator: Dongliang Mu <dzm91@hust.edu.cn> + +==== +CVEs +==== + +Common Vulnerabilities and Exposure (CVE®) 编号是一种明确的方式来 +识别、定义和登记公开披露的安全漏洞。随着时间的推移,它们在内核项目中的实用性 +已经下降,CVE编号经常以不适当的方式和不适当的原因被分配。因此,内核开发社区 +倾向于避免使用它们。然而,分配CVE与其他形式的安全标识符的持续压力,以及内核 +社区之外的个人和公司的持续滥用,已经清楚地表明内核社区应该控制这些CVE分配。 + +Linux内核开发团队确实有能力为潜在的Linux内核安全问题分配CVE。CVE的分配 +独立于 :doc:`安全漏洞报送流程</process/security-bugs>`。 + +所有分配给Linux内核的CVE列表都可以在linux-cve邮件列表的存档中找到,如 +https://lore.kernel.org/linux-cve-announce/ 所示。如果想获得已分配 +CVE的通知,请“订阅”该邮件列表。要获得分配的CVE通知,请订阅该邮件列表: +`订阅 <https://subspace.kernel.org/subscribing.html>`_。 + +过程 +======= + +作为正常稳定发布过程的一部分,可能存在安全问题的内核更改由负责CVE编号分配 +的开发人员识别,并自动为其分配CVE编号。这些CVE分配会作为经常性的通告经常 +发布在linux-cve-announce邮件列表上。 + +注意,由于Linux内核在系统中的特殊地位,几乎任何漏洞都可能被利用来危害内核 +的安全性,但是当漏洞被修复后,利用的可能性通常不明显。因此,CVE分配团队过于 +谨慎,并将CVE编号分配给他们识别的任何漏洞修复。这就解释了为什么Linux内核 +团队会发布大量的CVE。 + +如果CVE分配团队错过了任何用户认为应该分配CVE的特定修复,请发送电子邮件到 +<cve@kernel.org>,那里的团队将与您一起工作。请注意,任何潜在的安全问题 +不应被发送到此邮箱,它仅用于为已发布的内核树中的漏洞修复分配CVE。如果你觉得 +自己发现了一个未修复的安全问题,请按照 :doc:`安全漏洞报送流程 +</process/security-bugs>` 发送到Linux内核社区。 + +Linux内核不会给未修复的安全问题自动分配CVE;只有在安全修复可用且应用于 +稳定内核树后,CVE分配才会自动发生,并且它将通过安全修复的Git提交编号进行 +跟踪。如果有人希望在提交安全修复之前分配CVE,请联系内核CVE分配团队,从 +他们的一批保留编号中获得相应的CVE编号。 + +对于目前没有得到稳定与长期维护内核团队积极支持的内核版本中发现的任何问题, +都不会分配CVEs。当前支持的内核分支列表可以在 https://kernel.org/releases.html +上找到。 + +被分配CVE的争论 +========================= + +对于为特定内核修改分配的CVE,其争论或修改的权限仅属于受影响子系统的维护者。 +这一原则确保了漏洞报告的高度准确性和可问责性。只有那些具有深厚专业知识和 +对子系统深入了解的维护人员,才能有效评估内核漏洞的有效性和范围,并确定其适当的 +CVE指定策略。在此指定权限之外,任何争论或修改CVE的尝试都可能导致混乱、 +不准确的报告,并最终危及系统。 + +无效的CVE +============ + +如果发现的安全问题存在于仅由某Linux发行版支持的Linux内核中,即安全问题是 +由于Linux发行版所做的更改导致,或者Linux的发行版内核版本不再是Linux内核 +社区支持的内核版本,那么Linux内核CVE团队将不能分配CVE,必须从Linux +发行版本身请求。 + +内核CVE分配团队以外的任何团队对Linux内核支持版本分配的CVE都不应被 +视为有效CVE。请通知内核CVE分配团队,以便他们可以通过CNA修复措施使 +这些条目失效。 + +特定CVE的适用性 +============================== + +由于Linux内核可以以许多不同方式使用,外部用户可以通过许多不同方式访问它,或者 +根本没有访问,因此任何特定CVE的适用性取决于Linux用户,而不是内核CVE分配团队。 +请不要与我们联系来尝试确定任何特定CVE的适用性。 + +此外,由于源代码树非常大,而任何一个系统都只使用源代码树的一小部分,因此任何 +Linux用户都应该意识到,大量分配的CVEs与他们的系统无关。 + +简而言之,我们不知道您的用例,也不知道您使用的是内核的哪个部分,因此我们无法 +确定特定的CVE是否与您的系统相关。 + +与往常一样,最好采用所有发布的内核更改,因为它们是由许多社区成员在一个统一的 +整体中一起进行测试的,而不是作为个别的精选更改。还要注意,对于许多安全问题来 +说,整体问题的解决方案并不是在单个更改中找到的,而是在彼此之上的许多修复的总 +和。理想情况下,CVE将被分配给所有问题的所有修复,但有时我们将无法注意到一些 +修复,因此某些修复可能在没有CVE的情况下被采取。 diff --git a/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst index cf5f1fca3d92..c90ecb557811 100644 --- a/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst +++ b/Documentation/translations/zh_CN/process/embargoed-hardware-issues.rst @@ -177,7 +177,7 @@ CVE分配 AMD Tom Lendacky <thomas.lendacky@amd.com> IBM Intel Tony Luck <tony.luck@intel.com> - Qualcomm Trilok Soni <tsoni@codeaurora.org> + Qualcomm Trilok Soni <quic_tsoni@quicinc.com> Microsoft Sasha Levin <sashal@kernel.org> VMware diff --git a/Documentation/translations/zh_CN/process/index.rst b/Documentation/translations/zh_CN/process/index.rst index 3ca02d281be0..5c6c8ccdd50d 100644 --- a/Documentation/translations/zh_CN/process/index.rst +++ b/Documentation/translations/zh_CN/process/index.rst @@ -48,6 +48,7 @@ TODOLIST: :maxdepth: 1 embargoed-hardware-issues + cve TODOLIST: diff --git a/Documentation/translations/zh_CN/process/submitting-patches.rst b/Documentation/translations/zh_CN/process/submitting-patches.rst index f8978f02057c..7864107e60a8 100644 --- a/Documentation/translations/zh_CN/process/submitting-patches.rst +++ b/Documentation/translations/zh_CN/process/submitting-patches.rst @@ -333,10 +333,10 @@ Linus 和其他的内核开发者需要阅读和评论你提交的改动。对 未参与其开发。签署链应当反映补丁传播到维护者并最终传播到Linus所经过的 **真实** 路径,首个签署指明单个作者的主要作者身份。 -何时使用Acked-by:,CC:,和Co-Developed by: +何时使用Acked-by:,Cc:,和Co-developed-by: ------------------------------------------ -Singed-off-by: 标签表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。 +Signed-off-by: 标签表示签名者参与了补丁的开发,或者他/她在补丁的传递路径中。 如果一个人没有直接参与补丁的准备或处理,但希望表示并记录他们对补丁的批准/赞成, 那么他们可以要求在补丁的变更日志中添加一个Acked-by:。 @@ -358,8 +358,8 @@ Acked-by:不一定表示对整个补丁的确认。例如,如果一个补丁 Co-developed-by: 声明补丁是由多个开发人员共同创建的;当几个人在一个补丁上工 作时,它用于给出共同作者(除了From:所给出的作者之外)。因为Co-developed-by: 表示作者身份,所以每个Co-developed-by:必须紧跟在相关合作作者的签署之后。标准 -签署程序要求Singed-off-by:标签的顺序应尽可能反映补丁的时间历史,无论作者是通 -过From:还是Co-developed-by:表明。值得注意的是,最后一个Singed-off-by:必须是 +签署程序要求Signed-off-by:标签的顺序应尽可能反映补丁的时间历史,无论作者是通 +过From:还是Co-developed-by:表明。值得注意的是,最后一个Signed-off-by:必须是 提交补丁的开发人员。 注意,如果From:作者也是电子邮件标题的From:行中列出的人,则From:标签是可选的。 diff --git a/Documentation/translations/zh_CN/rust/arch-support.rst b/Documentation/translations/zh_CN/rust/arch-support.rst index afbd02afec45..abd708d48f82 100644 --- a/Documentation/translations/zh_CN/rust/arch-support.rst +++ b/Documentation/translations/zh_CN/rust/arch-support.rst @@ -16,8 +16,12 @@ 下面是目前可以工作的架构的一般总结。支持程度与 ``MAINTAINERS`` 文件中的``S`` 值相对应: -============ ================ ============================================== -架构 支持水平 限制因素 -============ ================ ============================================== -``x86`` Maintained 只有 ``x86_64`` -============ ================ ============================================== +============= ================ ============================================== +架构 支持水平 限制因素 +============= ================ ============================================== +``arm64`` Maintained 只有小端序 +``loongarch`` Maintained \- +``riscv`` Maintained 只有 ``riscv64`` +``um`` Maintained 只有 ``x86_64`` +``x86`` Maintained 只有 ``x86_64`` +============= ================ ============================================== diff --git a/Documentation/translations/zh_CN/rust/coding-guidelines.rst b/Documentation/translations/zh_CN/rust/coding-guidelines.rst index 6c0bdbbc5a2a..419143b938ed 100644 --- a/Documentation/translations/zh_CN/rust/coding-guidelines.rst +++ b/Documentation/translations/zh_CN/rust/coding-guidelines.rst @@ -157,6 +157,18 @@ https://commonmark.org/help/ https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html +此外,内核支持通过在链接目标前添加 ``srctree/`` 来创建相对于源代码树的链接。例如: + +.. code-block:: rust + + //! C header: [`include/linux/printk.h`](srctree/include/linux/printk.h) + +或者: + +.. code-block:: rust + + /// [`struct mutex`]: srctree/include/linux/mutex.h + 命名 ---- diff --git a/Documentation/translations/zh_CN/rust/general-information.rst b/Documentation/translations/zh_CN/rust/general-information.rst index 6b91dfe1834a..251f6ee2bb44 100644 --- a/Documentation/translations/zh_CN/rust/general-information.rst +++ b/Documentation/translations/zh_CN/rust/general-information.rst @@ -32,7 +32,7 @@ Rust内核代码使用其内置的文档生成器 ``rustdoc`` 进行记录。 要在你的网络浏览器中本地阅读该文档,请运行如:: - xdg-open rust/doc/kernel/index.html + xdg-open Documentation/output/rust/rustdoc/kernel/index.html 要了解如何编写文档,请看 coding-guidelines.rst 。 diff --git a/Documentation/translations/zh_CN/rust/quick-start.rst b/Documentation/translations/zh_CN/rust/quick-start.rst index a4b8e8a50a89..8616556ae4d7 100644 --- a/Documentation/translations/zh_CN/rust/quick-start.rst +++ b/Documentation/translations/zh_CN/rust/quick-start.rst @@ -37,13 +37,18 @@ rustc 需要一个特定版本的Rust编译器。较新的版本可能会也可能不会工作,因为就目前而言,内核依赖 于一些不稳定的Rust特性。 -如果使用的是 ``rustup`` ,请进入检出的源代码目录并运行:: +如果使用的是 ``rustup`` ,请进入内核编译目录(或者用 ``--path=<build-dir>`` 参数 +来 ``设置`` sub-command)并运行:: rustup override set $(scripts/min-tool-version.sh rustc) -或者从以下网址获取一个独立的安装程序或安装 ``rustup`` : ++这将配置你的工作目录使用正确版本的 ``rustc``,而不影响你的默认工具链。 - https://www.rust-lang.org +请注意覆盖应用当前的工作目录(和它的子目录)。 + +如果你使用 ``rustup``, 可以从下面的链接拉取一个单独的安装程序: + + https://forge.rust-lang.org/infra/other-installation-methods.html#standalone Rust标准库源代码 @@ -57,21 +62,23 @@ Rust标准库的源代码是必需的,因为构建系统会交叉编译 ``core 这些组件是按工具链安装的,因此以后升级Rust编译器版本需要重新添加组件。 -否则,如果使用独立的安装程序,可以将Rust仓库克隆到工具链的安装文件夹中:: +否则,如果使用独立的安装程序,可以将Rust源码树下载到安装工具链的文件夹中:: - git clone --recurse-submodules \ - --branch $(scripts/min-tool-version.sh rustc) \ - https://github.com/rust-lang/rust \ - $(rustc --print sysroot)/lib/rustlib/src/rust + curl -L "https://static.rust-lang.org/dist/rust-src-$(scripts/min-tool-version.sh rustc).tar.gz" | + tar -xzf - -C "$(rustc --print sysroot)/lib" \ + "rust-src-$(scripts/min-tool-version.sh rustc)/rust-src/lib/" \ + --strip-components=3 -在这种情况下,以后升级Rust编译器版本需要手动更新这个克隆的仓库。 +在这种情况下,以后升级Rust编译器版本需要手动更新这个源代码树(这可以通过移除 +``$(rustc --print sysroot)/lib/rustlib/src/rust`` ,然后重新执行上 +面的命令做到)。 libclang ******** ``bindgen`` 使用 ``libclang`` (LLVM的一部分)来理解内核中的C代码,这意味着需要安 -装LLVM;同在开启 ``CC=clang`` 或 ``LLVM=1`` 时编译内核一样。 +装LLVM;同在开启``LLVM=1`` 时编译内核一样。 Linux发行版中可能会有合适的包,所以最好先检查一下。 @@ -94,7 +101,20 @@ bindgen 通过以下方式安装它(注意,这将从源码下载并构建该工具):: - cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen + cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen-cli + +``bindgen`` 需要找到合适的 ``libclang`` 才能工作。如果没有找到(或者找到的 +``libclang`` 与应该使用的 ``libclang`` 不同),则可以使用 ``clang-sys`` +理解的环境变量(Rust绑定创建的 ``bindgen`` 用来访问 ``libclang``): + + +* ``LLVM_CONFIG_PATH`` 可以指向一个 ``llvm-config`` 可执行文件。 + +* 或者 ``LIBCLANG_PATH`` 可以指向 ``libclang`` 共享库或包含它的目录。 + +* 或者 ``CLANG_PATH`` 可以指向 ``clang`` 可执行文件。 + +详情请参阅 ``clang-sys`` 的文档: 开发依赖 @@ -163,7 +183,9 @@ rust-analyzer 一起使用,以实现语法高亮、补全、转到定义和其他功能。 ``rust-analyzer`` 需要一个配置文件, ``rust-project.json``, 它可以由 ``rust-analyzer`` -Make 目标生成。 +Make 目标生成:: + + make LLVM=1 rust-analyzer 配置 @@ -189,10 +211,6 @@ Rust支持(CONFIG_RUST)需要在 ``General setup`` 菜单中启用。在其 make LLVM=1 -对于不支持完整LLVM工具链的架构,使用:: - - make CC=clang - 使用GCC对某些配置也是可行的,但目前它是非常试验性的。 diff --git a/Documentation/translations/zh_CN/scheduler/sched-domains.rst b/Documentation/translations/zh_CN/scheduler/sched-domains.rst index e814d4c01141..06363169c56b 100644 --- a/Documentation/translations/zh_CN/scheduler/sched-domains.rst +++ b/Documentation/translations/zh_CN/scheduler/sched-domains.rst @@ -34,17 +34,17 @@ CPU共享。任意两个组的CPU掩码的交集不一定为空,如果是这 调度域中的负载均衡发生在调度组中。也就是说,每个组被视为一个实体。组的负载被定义为它 管辖的每个CPU的负载之和。仅当组的负载不均衡后,任务才在组之间发生迁移。 -在kernel/sched/core.c中,trigger_load_balance()在每个CPU上通过scheduler_tick() +在kernel/sched/core.c中,sched_balance_trigger()在每个CPU上通过sched_tick() 周期执行。在当前运行队列下一个定期调度再平衡事件到达后,它引发一个软中断。负载均衡真正 -的工作由run_rebalance_domains()->rebalance_domains()完成,在软中断上下文中执行 +的工作由sched_balance_softirq()->sched_balance_domains()完成,在软中断上下文中执行 (SCHED_SOFTIRQ)。 -后一个函数有两个入参:当前CPU的运行队列、它在scheduler_tick()调用时是否空闲。函数会从 +后一个函数有两个入参:当前CPU的运行队列、它在sched_tick()调用时是否空闲。函数会从 当前CPU所在的基调度域开始迭代执行,并沿着parent指针链向上进入更高层级的调度域。在迭代 过程中,函数会检查当前调度域是否已经耗尽了再平衡的时间间隔,如果是,它在该调度域运行 -load_balance()。接下来它检查父调度域(如果存在),再后来父调度域的父调度域,以此类推。 +sched_balance_rq()。接下来它检查父调度域(如果存在),再后来父调度域的父调度域,以此类推。 -起初,load_balance()查找当前调度域中最繁忙的调度组。如果成功,在该调度组管辖的全部CPU +起初,sched_balance_rq()查找当前调度域中最繁忙的调度组。如果成功,在该调度组管辖的全部CPU 的运行队列中找出最繁忙的运行队列。如能找到,对当前的CPU运行队列和新找到的最繁忙运行 队列均加锁,并把任务从最繁忙队列中迁移到当前CPU上。被迁移的任务数量等于在先前迭代执行 中计算出的该调度域的调度组的不均衡值。 diff --git a/Documentation/translations/zh_CN/scheduler/sched-stats.rst b/Documentation/translations/zh_CN/scheduler/sched-stats.rst index c5e0be663837..09eee2517610 100644 --- a/Documentation/translations/zh_CN/scheduler/sched-stats.rst +++ b/Documentation/translations/zh_CN/scheduler/sched-stats.rst @@ -75,42 +75,42 @@ domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 繁忙,新空闲): - 1) 当CPU空闲时,load_balance()在这个调度域中被调用了#次 - 2) 当CPU空闲时,load_balance()在这个调度域中被调用,但是发现负载无需 + 1) 当CPU空闲时,sched_balance_rq()在这个调度域中被调用了#次 + 2) 当CPU空闲时,sched_balance_rq()在这个调度域中被调用,但是发现负载无需 均衡#次 - 3) 当CPU空闲时,load_balance()在这个调度域中被调用,试图迁移1个或更多 + 3) 当CPU空闲时,sched_balance_rq()在这个调度域中被调用,试图迁移1个或更多 任务且失败了#次 - 4) 当CPU空闲时,load_balance()在这个调度域中被调用,发现不均衡(如果有) + 4) 当CPU空闲时,sched_balance_rq()在这个调度域中被调用,发现不均衡(如果有) #次 5) 当CPU空闲时,pull_task()在这个调度域中被调用#次 6) 当CPU空闲时,尽管目标任务是热缓存状态,pull_task()依然被调用#次 - 7) 当CPU空闲时,load_balance()在这个调度域中被调用,未能找到更繁忙的 + 7) 当CPU空闲时,sched_balance_rq()在这个调度域中被调用,未能找到更繁忙的 队列#次 8) 当CPU空闲时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组 #次 - 9) 当CPU繁忙时,load_balance()在这个调度域中被调用了#次 - 10) 当CPU繁忙时,load_balance()在这个调度域中被调用,但是发现负载无需 + 9) 当CPU繁忙时,sched_balance_rq()在这个调度域中被调用了#次 + 10) 当CPU繁忙时,sched_balance_rq()在这个调度域中被调用,但是发现负载无需 均衡#次 - 11) 当CPU繁忙时,load_balance()在这个调度域中被调用,试图迁移1个或更多 + 11) 当CPU繁忙时,sched_balance_rq()在这个调度域中被调用,试图迁移1个或更多 任务且失败了#次 - 12) 当CPU繁忙时,load_balance()在这个调度域中被调用,发现不均衡(如果有) + 12) 当CPU繁忙时,sched_balance_rq()在这个调度域中被调用,发现不均衡(如果有) #次 13) 当CPU繁忙时,pull_task()在这个调度域中被调用#次 14) 当CPU繁忙时,尽管目标任务是热缓存状态,pull_task()依然被调用#次 - 15) 当CPU繁忙时,load_balance()在这个调度域中被调用,未能找到更繁忙的 + 15) 当CPU繁忙时,sched_balance_rq()在这个调度域中被调用,未能找到更繁忙的 队列#次 16) 当CPU繁忙时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组 #次 - 17) 当CPU新空闲时,load_balance()在这个调度域中被调用了#次 - 18) 当CPU新空闲时,load_balance()在这个调度域中被调用,但是发现负载无需 + 17) 当CPU新空闲时,sched_balance_rq()在这个调度域中被调用了#次 + 18) 当CPU新空闲时,sched_balance_rq()在这个调度域中被调用,但是发现负载无需 均衡#次 - 19) 当CPU新空闲时,load_balance()在这个调度域中被调用,试图迁移1个或更多 + 19) 当CPU新空闲时,sched_balance_rq()在这个调度域中被调用,试图迁移1个或更多 任务且失败了#次 - 20) 当CPU新空闲时,load_balance()在这个调度域中被调用,发现不均衡(如果有) + 20) 当CPU新空闲时,sched_balance_rq()在这个调度域中被调用,发现不均衡(如果有) #次 21) 当CPU新空闲时,pull_task()在这个调度域中被调用#次 22) 当CPU新空闲时,尽管目标任务是热缓存状态,pull_task()依然被调用#次 - 23) 当CPU新空闲时,load_balance()在这个调度域中被调用,未能找到更繁忙的 + 23) 当CPU新空闲时,sched_balance_rq()在这个调度域中被调用,未能找到更繁忙的 队列#次 24) 当CPU新空闲时,在调度域中找到了更繁忙的队列,但未找到更繁忙的调度组 #次 diff --git a/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst index 845b932bf935..aefad87e9099 100644 --- a/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst +++ b/Documentation/translations/zh_CN/userspace-api/accelerators/ocxl.rst @@ -53,7 +53,7 @@ OpenCAPI定义了一个在物理链路层上实现的数据链路层(TL)和 Processor:处理器 Memory:内存 - Accelerated Function Unit:加速函数单元 + Accelerated Function Unit:加速功能单元 @@ -97,7 +97,7 @@ OpenCAPI拥有AFU向主机进程发送中断的可能性。它通过定义在传 ======== 驱动为每个在物理设备上发现的AFU创建一个字符设备。一个物理设备可能拥有多个 -函数,一个函数可以拥有多个AFU。不过编写这篇文档之时,只对导出一个AFU的设备 +功能,一个功能可以拥有多个AFU。不过编写这篇文档之时,只对导出一个AFU的设备 测试过。 字符设备可以在 /dev/ocxl/ 中被找到,其命名为: |