Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,291 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/README.rst
:译者:
吴想成 Wu XiangCheng <bobwxc@email.cn>
Linux内核6.x版本 <http://kernel.org/>
=========================================
以下是Linux版本6的发行注记。仔细阅读它们,
它们会告诉你这些都是什么,解释如何安装内核,以及遇到问题时该如何做。
什么是Linux?
---------------
Linux是Unix操作系统的克隆版本,由Linus Torvalds在一个松散的网络黑客
(Hacker,无贬义)团队的帮助下从头开始编写。它旨在实现兼容POSIX和
单一UNIX规范。
它具有在现代成熟的Unix中应当具有的所有功能,包括真正的多任务处理、虚拟内存、
共享库、按需加载、共享的写时拷贝(COW)可执行文件、恰当的内存管理以及包括
IPv4和IPv6在内的复合网络栈。
Linux在GNU通用公共许可证,版本2(GNU GPLv2)下分发,详见随附的COPYING文件。
它能在什么样的硬件上运行?
-----------------------------
虽然Linux最初是为32位的x86 PC机(386或更高版本)开发的,但今天它也能运行在
(至少)Compaq Alpha AXP、Sun SPARC与UltraSPARC、Motorola 68000、PowerPC、
PowerPC64、ARM、Hitachi SuperH、Cell、IBM S/390、MIPS、HP PA-RISC、Intel
IA-64、DEC VAX、AMD x86-64 Xtensa和ARC架构上。
Linux很容易移植到大多数通用的32位或64位体系架构,只要它们有一个分页内存管理
单元(PMMU)和一个移植的GNU C编译器(gcc;GNU Compiler Collection,GCC的一
部分)。Linux也被移植到许多没有PMMU的体系架构中,尽管功能显然受到了一定的
限制。
Linux也被移植到了其自己上。现在可以将内核作为用户空间应用程序运行——这被
称为用户模式Linux(UML)。
文档
-----
因特网上和书籍上都有大量的电子文档,既有Linux专属文档,也有与一般UNIX问题相关
的文档。我建议在任何Linux FTP站点上查找LDP(Linux文档项目)书籍的文档子目录。
本自述文件并不是关于系统的文档:有更好的可用资源。
- 因特网上和书籍上都有大量的(电子)文档,既有Linux专属文档,也有与普通
UNIX问题相关的文档。我建议在任何有LDP(Linux文档项目)书籍的Linux FTP
站点上查找文档子目录。本自述文件并不是关于系统的文档:有更好的可用资源。
- 文档/子目录中有各种自述文件:例如,这些文件通常包含一些特定驱动程序的
内核安装说明。请阅读
:ref:`Documentation/process/changes.rst <changes>` 文件,它包含了升级内核
可能会导致的问题的相关信息。
安装内核源代码
---------------
- 如果您要安装完整的源代码,请把内核tar档案包放在您有权限的目录中(例如您
的主目录)并将其解包::
xz -cd linux-6.x.tar.xz | tar xvf -
将“X”替换成最新内核的版本号。
【不要】使用 /usr/src/linux 目录!这里有一组库头文件使用的内核头文件
(通常是不完整的)。它们应该与库匹配,而不是被内核的变化搞得一团糟。
- 您还可以通过打补丁在6.x版本之间升级。补丁以xz格式分发。要通过打补丁进行
安装,请获取所有较新的补丁文件,进入内核源代码(linux-6.x)的目录并
执行::
xz -cd ../patch-6.x.xz | patch -p1
请【按顺序】替换所有大于当前源代码树版本的“x”,这样就可以了。您可能想要
删除备份文件(文件名类似xxx~ 或 xxx.orig),并确保没有失败的补丁(文件名
类似xxx# 或 xxx.rej)。如果有,不是你就是我犯了错误。
与6.x内核的补丁不同,6.x.y内核(也称为稳定版内核)的补丁不是增量的,而是
直接应用于基本的6.x内核。例如,如果您的基本内核是6.0,并且希望应用6.0.3
补丁,则不应先应用6.0.1和6.0.2的补丁。类似地,如果您运行的是6.0.2内核,
并且希望跳转到6.0.3,那么在应用6.0.3补丁之前,必须首先撤销6.0.2补丁
(即patch -R)。更多关于这方面的内容,请阅读
:ref:`Documentation/process/applying-patches.rst <applying_patches>` 。
或者,脚本 patch-kernel 可以用来自动化这个过程。它能确定当前内核版本并
应用找到的所有补丁::
linux/scripts/patch-kernel linux
上面命令中的第一个参数是内核源代码的位置。补丁是在当前目录应用的,但是
可以将另一个目录指定为第二个参数。
- 确保没有过时的 .o 文件和依赖项::
cd linux
make mrproper
现在您应该已经正确安装了源代码。
软件要求
---------
编译和运行6.x内核需要各种软件包的最新版本。请参考
:ref:`Documentation/process/changes.rst <changes>`
来了解最低版本要求以及如何升级软件包。请注意,使用过旧版本的这些包可能会
导致很难追踪的间接错误,因此不要以为在生成或操作过程中出现明显问题时可以
只更新包。
为内核建立目录
---------------
编译内核时,默认情况下所有输出文件都将与内核源代码放在一起。使用
``make O=output/dir`` 选项可以为输出文件(包括 .config)指定备用位置。
例如::
kernel source code: /usr/src/linux-6.x
build directory: /home/name/build/kernel
要配置和构建内核,请使用::
cd /usr/src/linux-6.x
make O=/home/name/build/kernel menuconfig
make O=/home/name/build/kernel
sudo make O=/home/name/build/kernel modules_install install
请注意:如果使用了 ``O=output/dir`` 选项,那么它必须用于make的所有调用。
配置内核
---------
即使只升级一个小版本,也不要跳过此步骤。每个版本中都会添加新的配置选项,
如果配置文件没有按预定设置,就会出现奇怪的问题。如果您想以最少的工作量
将现有配置升级到新版本,请使用 ``make oldconfig`` ,它只会询问您新配置
选项的答案。
- 其他配置命令包括::
"make config" 纯文本界面。
"make menuconfig" 基于文本的彩色菜单、选项列表和对话框。
"make nconfig" 增强的基于文本的彩色菜单。
"make xconfig" 基于Qt的配置工具。
"make gconfig" 基于GTK的配置工具。
"make oldconfig" 基于现有的 ./.config 文件选择所有选项,并询问
新配置选项。
"make olddefconfig"
类似上一个,但不询问直接将新选项设置为默认值。
"make defconfig" 根据体系架构,使用arch/$arch/defconfig或
arch/$arch/configs/${PLATFORM}_defconfig中的
默认选项值创建./.config文件。
"make ${PLATFORM}_defconfig"
使用arch/$arch/configs/${PLATFORM}_defconfig中
的默认选项值创建一个./.config文件。
用“make help”来获取您体系架构中所有可用平台的列表。
"make allyesconfig"
通过尽可能将选项值设置为“y”,创建一个
./.config文件。
"make allmodconfig"
通过尽可能将选项值设置为“m”,创建一个
./.config文件。
"make allnoconfig" 通过尽可能将选项值设置为“n”,创建一个
./.config文件。
"make randconfig" 通过随机设置选项值来创建./.config文件。
"make localmodconfig" 基于当前配置和加载的模块(lsmod)创建配置。禁用
已加载的模块不需要的任何模块选项。
要为另一台计算机创建localmodconfig,请将该计算机
的lsmod存储到一个文件中,并将其作为lsmod参数传入。
此外,通过在参数LMC_KEEP中指定模块的路径,可以将
模块保留在某些文件夹或kconfig文件中。
target$ lsmod > /tmp/mylsmod
target$ scp /tmp/mylsmod host:/tmp
host$ make LSMOD=/tmp/mylsmod \
LMC_KEEP="drivers/usb:drivers/gpu:fs" \
localmodconfig
上述方法在交叉编译时也适用。
"make localyesconfig" 与localmodconfig类似,只是它会将所有模块选项转换
为内置(=y)。你可以同时通过LMC_KEEP保留模块。
"make kvm_guest.config"
为kvm客户机内核支持启用其他选项。
"make xen.config" 为xen dom0客户机内核支持启用其他选项。
"make tinyconfig" 配置尽可能小的内核。
更多关于使用Linux内核配置工具的信息,见文档
Documentation/kbuild/kconfig.rst。
- ``make config`` 注意事项:
- 包含不必要的驱动程序会使内核变大,并且在某些情况下会导致问题:
探测不存在的控制器卡可能会混淆其他控制器。
- 如果存在协处理器,则编译了数学仿真的内核仍将使用协处理器:在
这种情况下,数学仿真永远不会被使用。内核会稍微大一点,但不管
是否有数学协处理器,都可以在不同的机器上工作。
- “kernel hacking”配置细节通常会导致更大或更慢的内核(或两者
兼而有之),甚至可以通过配置一些例程来主动尝试破坏坏代码以发现
内核问题,从而降低内核的稳定性(kmalloc())。因此,您可能应该
用于研究“开发”、“实验”或“调试”特性相关问题。
编译内核
---------
- 确保您至少有gcc 8.1可用。
有关更多信息,请参阅 :ref:`Documentation/process/changes.rst <changes>` 。
- 执行 ``make`` 来创建压缩内核映像。如果您安装了lilo以适配内核makefile,
那么也可以进行 ``make install`` ,但是您可能需要先检查特定的lilo设置。
实际安装必须以root身份执行,但任何正常构建都不需要。
无须徒然使用root身份。
- 如果您将内核的任何部分配置为模块,那么还必须执行 ``make modules_install`` 。
- 详细的内核编译/生成输出:
通常,内核构建系统在相当安静的模式下运行(但不是完全安静)。但是有时您或
其他内核开发人员需要看到编译、链接或其他命令的执行过程。为此,可使用
“verbose(详细)”构建模式。
向 ``make`` 命令传递 ``V=1`` 来实现,例如::
make V=1 all
如需构建系统也给出内个目标重建的愿意,请使用 ``V=2`` 。默认为 ``V=0`` 。
- 准备一个备份内核以防出错。对于开发版本尤其如此,因为每个新版本都包含
尚未调试的新代码。也要确保保留与该内核对应的模块的备份。如果要安装
与工作内核版本号相同的新内核,请在进行 ``make modules_install`` 安装
之前备份modules目录。
或者,在编译之前,使用内核配置选项“LOCALVERSION”向常规内核版本附加
一个唯一的后缀。LOCALVERSION可以在“General Setup”菜单中设置。
- 为了引导新内核,您需要将内核映像(例如编译后的
.../linux/arch/x86/boot/bzImage)复制到常规可引导内核的位置。
- 不再支持在没有LILO等启动装载程序帮助的情况下直接从软盘引导内核。
如果从硬盘引导Linux,很可能使用LILO,它使用/etc/lilo.conf文件中
指定的内核映像文件。内核映像文件通常是/vmlinuz、/boot/vmlinuz、
/bzImage或/boot/bzImage。使用新内核前,请保存旧映像的副本,并复制
新映像覆盖旧映像。然后您【必须重新运行LILO】来更新加载映射!否则,
将无法启动新的内核映像。
重新安装LILO通常需要运行/sbin/LILO。您可能希望编辑/etc/lilo.conf
文件为旧内核映像指定一个条目(例如/vmlinux.old)防止新的不能正常
工作。有关更多信息,请参阅LILO文档。
重新安装LILO之后,您应该就已经准备好了。关闭系统,重新启动,尽情
享受吧!
如果需要更改内核映像中的默认根设备、视频模式等,请在适当的地方使用
启动装载程序的引导选项。无需重新编译内核即可更改这些参数。
- 使用新内核重新启动并享受它吧。
若遇到问题
-----------
如果您发现了一些可能由于内核缺陷所导致的问题,请参阅:
Documentation/translations/zh_CN/admin-guide/reporting-issues.rst 。
想要理解内核错误报告,请参阅:
Documentation/translations/zh_CN/admin-guide/bug-hunting.rst 。
更多用GDB调试内核的信息,请参阅:
Documentation/translations/zh_CN/dev-tools/gdb-kernel-debugging.rst
和 Documentation/process/debugging/kgdb.rst 。
@@ -0,0 +1,293 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/bootconfig.rst
:译者: 吴想成 Wu XiangCheng <bobwxc@email.cn>
========
引导配置
========
:作者: Masami Hiramatsu <mhiramat@kernel.org>
概述
====
引导配置扩展了现有的内核命令行,以一种更有效率的方式在引导内核时进一步支持
键值数据。这允许管理员传递一份结构化关键字的配置文件。
配置文件语法
============
引导配置文件的语法采用非常简单的键值结构。每个关键字由点连接的单词组成,键
和值由 ``=`` 连接。值以分号( ``;`` )或换行符( ``\n`` )结尾。数组值中每
个元素由逗号( ``,`` )分隔。::
KEY[.WORD[...]] = VALUE[, VALUE2[...]][;]
与内核命令行语法不同,逗号和 ``=`` 周围允许有空格。
关键字只允许包含字母、数字、连字符( ``-`` )和下划线( ``_`` )。值可包含
可打印字符和空格,但分号( ``;`` )、换行符( ``\n`` )、逗号( ``,`` )、
井号( ``#`` )和右大括号( ``}`` )等分隔符除外。
如果你需要在值中使用这些分隔符,可以用双引号( ``"VALUE"`` )或单引号
( ``'VALUE'`` )括起来。注意,引号无法转义。
键的值可以为空或不存在。这些键用于检查该键是否存在(类似布尔值)。
键值语法
--------
引导配置文件语法允许用户通过大括号合并键名部分相同的关键字。例如::
foo.bar.baz = value1
foo.bar.qux.quux = value2
也可以写成::
foo.bar {
baz = value1
qux.quux = value2
}
或者更紧凑一些,写成::
foo.bar { baz = value1; qux.quux = value2 }
在这两种样式中,引导解析时相同的关键字都会自动合并。因此可以追加类似的树或
键值。
相同关键字的值
--------------
禁止两个或多个值或数组共享同一个关键字。例如::
foo = bar, baz
foo = qux # !错误! 我们不可以重定义相同的关键字
如果你想要更新值,必须显式使用覆盖操作符 ``:=`` 。例如::
foo = bar, baz
foo := qux
这样 ``foo`` 关键字的值就变成了 ``qux`` 。这对于通过添加(部分)自定义引导
配置来覆盖默认值非常有用,免于解析默认引导配置。
如果你想对现有关键字追加值作为数组成员,可以使用 ``+=`` 操作符。例如::
foo = bar, baz
foo += qux
这样, ``foo`` 关键字就同时拥有了 ``bar`` , ``baz`` 和 ``qux`` 。
此外,父关键字下可同时存在值和子关键字。
例如,下列配置是可行的。::
foo = value1
foo.bar = value2
foo := value3 # 这会更新foo的值。
注意,裸值不能直接放进结构化关键字中,必须在大括号外定义它。例如::
foo {
bar = value1
bar {
baz = value2
qux = value3
}
}
同时,关键字下值节点的顺序是固定的。如果值和子关键字同时存在,值永远是该关
键字的第一个子节点。因此如果用户先指定子关键字,如::
foo.bar = value1
foo = value2
则在程序(和/proc/bootconfig)中,它会按如下显示::
foo = value2
foo.bar = value1
注释
----
配置语法接受shell脚本风格的注释。注释以井号( ``#`` )开始,到换行符
( ``\n`` )结束。
::
# comment line
foo = value # value is set to foo.
bar = 1, # 1st element
2, # 2nd element
3 # 3rd element
会被解析为::
foo = value
bar = 1, 2, 3
注意你不能把注释放在值和分隔符( ``,`` 或 ``;`` )之间。如下配置语法是错误的::
key = 1 # comment
,2
/proc/bootconfig
================
/proc/bootconfig是引导配置的用户空间接口。与/proc/cmdline不同,此文件内容以
键值列表样式显示。
每个键值对一行,样式如下::
KEY[.WORDS...] = "[VALUE]"[,"VALUE2"...]
用引导配置引导内核
==================
用引导配置引导内核有两种方法:将引导配置附加到initrd镜像或直接嵌入内核中。
*initrd: initial RAM disk,初始内存磁盘*
将引导配置附加到initrd
----------------------
由于默认情况下引导配置文件是用initrd加载的,因此它将被添加到initrd(initramfs)
镜像文件的末尾,其中包含填充、大小、校验值和12字节幻数,如下所示::
[initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
大小和校验值为小端序存放的32位无符号值。
当引导配置被加到initrd镜像时,整个文件大小会对齐到4字节。空字符( ``\0`` )
会填补对齐空隙。因此 ``size`` 就是引导配置文件的长度+填充的字节。
Linux内核在内存中解码initrd镜像的最后部分以获取引导配置数据。由于这种“背负式”
的方法,只要引导加载器传递了正确的initrd文件大小,就无需更改或更新引导加载器
和内核镜像本身。如果引导加载器意外传递了更长的大小,内核将无法找到引导配置数
据。
Linux内核在tools/bootconfig下提供了 ``bootconfig`` 命令来完成此操作,管理员
可以用它从initrd镜像中删除或追加配置文件。你可以用以下命令来构建它::
# make -C tools/bootconfig
要向initrd镜像添加你的引导配置文件,请按如下命令操作(旧数据会自动移除)::
# tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
要从镜像中移除配置,可以使用-d选项::
# tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
然后在内核命令行上添加 ``bootconfig`` 告诉内核去initrd文件末尾寻找内核配置。
将引导配置嵌入内核
------------------
如果你不能使用initrd,也可以通过Kconfig选项将引导配置文件嵌入内核中。在此情
况下,你需要用以下选项重新编译内核::
CONFIG_BOOT_CONFIG_EMBED=y
CONFIG_BOOT_CONFIG_EMBED_FILE="/引导配置/文件/的/路径"
``CONFIG_BOOT_CONFIG_EMBED_FILE`` 需要从源码树或对象树开始的引导配置文件的
绝对/相对路径。内核会将其嵌入作为默认引导配置。
与将引导配置附加到initrd一样,你也需要在内核命令行上添加 ``bootconfig`` 告诉
内核去启用内嵌的引导配置。
注意,即使你已经设置了此选项,仍可用附加到initrd的其他引导配置覆盖内嵌的引导
配置。
通过引导配置传递内核参数
========================
除了内核命令行,引导配置也可以用于传递内核参数。所有 ``kernel`` 关键字下的键
值对都将直接传递给内核命令行。此外, ``init`` 下的键值对将通过命令行传递给
init进程。参数按以下顺序与用户给定的内核命令行字符串相连,因此命令行参数可以
覆盖引导配置参数(这取决于子系统如何处理参数,但通常前面的参数将被后面的参数
覆盖)::
[bootconfig params][cmdline params] -- [bootconfig init params][cmdline init params]
如果引导配置文件给出的kernel/init参数是::
kernel {
root = 01234567-89ab-cdef-0123-456789abcd
}
init {
splash
}
这将被复制到内核命令行字符串中,如下所示::
root="01234567-89ab-cdef-0123-456789abcd" -- splash
如果用户给出的其他命令行是::
ro bootconfig -- quiet
则最后的内核命令行如下::
root="01234567-89ab-cdef-0123-456789abcd" ro bootconfig -- splash quiet
配置文件的限制
==============
当前最大的配置大小是32KB,关键字总数(不是键值条目)必须少于1024个节点。
注意:这不是条目数而是节点数,条目必须消耗超过2个节点(一个关键字和一个值)。
所以从理论上讲最多512个键值对。如果关键字平均包含3个单词,则可有256个键值对。
在大多数情况下,配置项的数量将少于100个条目,小于8KB,因此这应该足够了。如果
节点数超过1024,解析器将返回错误,即使文件大小小于32KB。(请注意,此最大尺寸
不包括填充的空字符。)
无论如何,因为 ``bootconfig`` 命令在附加启动配置到initrd映像时会验证它,用户
可以在引导之前注意到它。
引导配置API
===========
用户可以查询或遍历键值对,也可以查找(前缀)根关键字节点,并在查找该节点下的
键值。
如果您有一个关键字字符串,则可以直接使用 xbc_find_value() 查询该键的值。如果
你想知道引导配置里有哪些关键字,可以使用 xbc_for_each_key_value() 迭代键值对。
请注意,您需要使用 xbc_array_for_each_value() 访问数组的值,例如::
vnode = NULL;
xbc_find_value("key.word", &vnode);
if (vnode && xbc_node_is_array(vnode))
xbc_array_for_each_value(vnode, value) {
printk("%s ", value);
}
如果您想查找具有前缀字符串的键,可以使用 xbc_find_node() 通过前缀字符串查找
节点,然后用 xbc_node_for_each_key_value() 迭代前缀节点下的键。
但最典型的用法是获取前缀下的命名值或前缀下的命名数组,例如::
root = xbc_find_node("key.prefix");
value = xbc_node_find_value(root, "option", &vnode);
...
xbc_node_for_each_array_value(root, "array-option", value, anode) {
...
}
这将访问值“key.prefix.option”的值和“key.prefix.array-option”的数组。
锁是不需要的,因为在初始化之后配置只读。如果需要修改,必须复制所有数据和关键字。
函数与结构体
============
相关定义的kernel-doc参见:
- include/linux/bootconfig.h
- lib/bootconfig.c
@@ -0,0 +1,81 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :doc:`../../../admin-guide/bug-bisect`
:译者:
吴想成 Wu XiangCheng <bobwxc@email.cn>
二分(bisect)缺陷
+++++++++++++++++++
(英文版)最后更新:2016年10月28日
引言
=====
始终尝试由来自kernel.org的源代码构建的最新内核。如果您没有信心这样做,请将
错误报告给您的发行版供应商,而不是内核开发人员。
找到缺陷(bug)并不总是那么容易,不过仍然得去找。如果你找不到它,不要放弃。
尽可能多的向相关维护人员报告您发现的信息。请参阅MAINTAINERS文件以了解您所
关注的子系统的维护人员。
在提交错误报告之前,请阅读“Documentation/admin-guide/reporting-issues.rst”。
设备未出现(Devices not appearing)
====================================
这通常是由udev/systemd引起的。在将其归咎于内核之前先检查一下。
查找导致缺陷的补丁
===================
使用 ``git`` 提供的工具可以很容易地找到缺陷,只要缺陷是可复现的。
操作步骤:
- 从git源代码构建内核
- 以此开始二分 [#f1]_::
$ git bisect start
- 标记损坏的变更集::
$ git bisect bad [commit]
- 标记正常工作的变更集::
$ git bisect good [commit]
- 重新构建内核并测试
- 使用以下任一与git bisect进行交互::
$ git bisect good
或::
$ git bisect bad
这取决于您测试的变更集上是否有缺陷
- 在一些交互之后,git bisect将给出可能导致缺陷的变更集。
- 例如,如果您知道当前版本有问题,而4.8版本是正常的,则可以执行以下操作::
$ git bisect start
$ git bisect bad # Current version is bad
$ git bisect good v4.8
.. [#f1] 您可以(可选地)在开始git bisect的时候提供good或bad参数
``git bisect start [BAD] [GOOD]``
如需进一步参考,请阅读:
- ``git-bisect`` 的手册页
- `Fighting regressions with git bisect(用git bisect解决回归)
<https://www.kernel.org/pub/software/scm/git/docs/git-bisect-lk2009.html>`_
- `Fully automated bisecting with "git bisect run"(使用git bisect run
来全自动二分) <https://lwn.net/Articles/317154>`_
- `Using Git bisect to figure out when brokenness was introduced
(使用Git二分来找出何时引入了错误) <http://webchick.net/node/99>`_
@@ -0,0 +1,331 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :doc:`../../../admin-guide/bug-hunting`
:译者:
吴想成 Wu XiangCheng <bobwxc@email.cn>
追踪缺陷
=========
内核错误报告通常附带如下堆栈转储::
------------[ cut here ]------------
WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70
Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core]
CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1
Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009
00000000 c12ba080 00000000 00000000 c103ed6a c1616014 00000001 00006dc6
c1615862 00000454 c109e8a7 c109e8a7 00000009 ffffffff 00000000 f13f6a10
f5f5a600 c103ee33 00000009 00000000 00000000 c109e8a7 f80ca4d0 c109f617
Call Trace:
[<c12ba080>] ? dump_stack+0x44/0x64
[<c103ed6a>] ? __warn+0xfa/0x120
[<c109e8a7>] ? module_put+0x57/0x70
[<c109e8a7>] ? module_put+0x57/0x70
[<c103ee33>] ? warn_slowpath_null+0x23/0x30
[<c109e8a7>] ? module_put+0x57/0x70
[<f80ca4d0>] ? gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk]
[<c109f617>] ? symbol_put_addr+0x27/0x50
[<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
[<f80bb3bf>] ? dvb_usb_exit+0x2f/0xd0 [dvb_usb]
[<c13d03bc>] ? usb_disable_endpoint+0x7c/0xb0
[<f80bb48a>] ? dvb_usb_device_exit+0x2a/0x50 [dvb_usb]
[<c13d2882>] ? usb_unbind_interface+0x62/0x250
[<c136b514>] ? __pm_runtime_idle+0x44/0x70
[<c13620d8>] ? __device_release_driver+0x78/0x120
[<c1362907>] ? driver_detach+0x87/0x90
[<c1361c48>] ? bus_remove_driver+0x38/0x90
[<c13d1c18>] ? usb_deregister+0x58/0xb0
[<c109fbb0>] ? SyS_delete_module+0x130/0x1f0
[<c1055654>] ? task_work_run+0x64/0x80
[<c1000fa5>] ? exit_to_usermode_loop+0x85/0x90
[<c10013f0>] ? do_fast_syscall_32+0x80/0x130
[<c1549f43>] ? sysenter_past_esp+0x40/0x6a
---[ end trace 6ebc60ef3981792f ]---
这样的堆栈跟踪提供了足够的信息来识别内核源代码中发生错误的那一行。根据问题的
严重性,它还可能包含 **“Oops”** 一词,比如::
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<c06969d4>] iret_exc+0x7d0/0xa59
*pdpt = 000000002258a001 *pde = 0000000000000000
Oops: 0002 [#1] PREEMPT SMP
...
尽管有 **Oops** 或其他类型的堆栈跟踪,但通常需要找到出问题的行来识别和处理缺
陷。在本章中,我们将参考“Oops”来了解需要分析的各种堆栈跟踪。
如果内核是用 ``CONFIG_DEBUG_INFO`` 编译的,那么可以使用文件:
`scripts/decode_stacktrace.sh` 。
链接的模块
-----------
受到污染或正在加载/卸载的模块用“(…)”标记,污染标志在
`Documentation/admin-guide/tainted-kernels.rst` 文件中进行了描述,“正在被加
载”用“+”标注,“正在被卸载”用“-”标注。
Oops消息在哪?
---------------
通常,Oops文本由klogd从内核缓冲区读取,然后交给 ``syslogd`` ,后者将其写入
syslog文件,通常是 ``/var/log/messages`` (取决于 ``/etc/syslog.conf`` )。
在使用systemd的系统上,它也可以由 ``journald`` 守护进程存储,并通过运行
``journalctl`` 命令进行访问。
有时 ``klogd`` 会挂掉,这种情况下您可以运行 ``dmesg > file`` 从内核缓冲区
读取数据并保存它。或者您可以 ``cat /proc/kmsg > file`` ,但是您必须适时
中断以停止传输,因为 ``kmsg`` 是一个“永无止境的文件”。
如果机器严重崩溃,无法输入命令或磁盘不可用,那还有三个选项:
(1) 手动复制屏幕上的文本,并在机器重新启动后输入。很难受,但这是突然崩溃下
唯一的选择。或者你可以用数码相机拍下屏幕——虽然不那么好,但总比什么都没
有好。如果消息滚动超出控制台顶部,使用更高分辨率(例如 ``vga=791`` )
引导启动将允许您阅读更多文本。(警告:这需要 ``vesafb`` ,因此对“早期”
的Oppses没有帮助)
(2) 从串口终端启动(参见
:ref:`Documentation/admin-guide/serial-console.rst <serial_console>` ),
在另一台机器上运行调制解调器然后用你喜欢的通信程序捕获输出。
Minicom运行良好。
(3) 使用Kdump(参阅 Documentation/admin-guide/kdump/kdump.rst ),使用
Documentation/admin-guide/kdump/gdbmacros.txt 中的dmesg gdbmacro从旧内存
中提取内核环形缓冲区。
找到缺陷位置
-------------
如果你能指出缺陷在内核源代码中的位置,则报告缺陷的效果会非常好。这有两种方法。
通常来说使用 ``gdb`` 会比较容易,不过内核需要用调试信息来预编译。
gdb
^^^^
GNU 调试器(GNU debugger, ``gdb`` )是从 ``vmlinux`` 文件中找出OOPS的确切
文件和行号的最佳方法。
在使用 ``CONFIG_DEBUG_INFO`` 编译的内核上使用gdb效果最好。可通过运行以下命令
进行设置::
$ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
在用 ``CONFIG_DEBUG_INFO`` 编译的内核上,你可以直接从OOPS复制EIP值::
EIP: 0060:[<c021e50e>] Not tainted VLI
并使用GDB来将其翻译成可读形式::
$ gdb vmlinux
(gdb) l *0xc021e50e
如果没有启用 ``CONFIG_DEBUG_INFO`` ,则使用OOPS的函数偏移::
EIP is at vt_ioctl+0xda8/0x1482
并在启用 ``CONFIG_DEBUG_INFO`` 的情况下重新编译内核::
$ ./scripts/config -d COMPILE_TEST -e DEBUG_KERNEL -e DEBUG_INFO
$ make vmlinux
$ gdb vmlinux
(gdb) l *vt_ioctl+0xda8
0x1888 is in vt_ioctl (drivers/tty/vt/vt_ioctl.c:293).
288 {
289 struct vc_data *vc = NULL;
290 int ret = 0;
291
292 console_lock();
293 if (VT_BUSY(vc_num))
294 ret = -EBUSY;
295 else if (vc_num)
296 vc = vc_deallocate(vc_num);
297 console_unlock();
或者若您想要更详细的显示::
(gdb) p vt_ioctl
$1 = {int (struct tty_struct *, unsigned int, unsigned long)} 0xae0 <vt_ioctl>
(gdb) l *0xae0+0xda8
您也可以使用对象文件作为替代::
$ make drivers/tty/
$ gdb drivers/tty/vt/vt_ioctl.o
(gdb) l *vt_ioctl+0xda8
如果你有调用跟踪,类似::
Call Trace:
[<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5
[<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e
[<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee
...
这表明问题可能在 :jbd: 模块中。您可以在gdb中加载该模块并列出相关代码::
$ gdb fs/jbd/jbd.ko
(gdb) l *log_wait_commit+0xa3
.. note::
您还可以对堆栈跟踪处的任何函数调用执行相同的操作,例如::
[<f80bc9ca>] ? dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb]
上述调用发生的位置可以通过以下方式看到::
$ gdb drivers/media/usb/dvb-usb/dvb-usb.o
(gdb) l *dvb_usb_adapter_frontend_exit+0x3a
objdump
^^^^^^^^
要调试内核,请使用objdump并从崩溃输出中查找十六进制偏移,以找到有效的代码/汇
编行。如果没有调试符号,您将看到所示例程的汇编程序代码,但是如果内核有调试
符号,C代码也将可见(调试符号可以在内核配置菜单的hacking项中启用)。例如::
$ objdump -r -S -l --disassemble net/ipv4/tcp.o
.. note::
您需要处于内核树的顶层以便此获得您的C文件。
如果您无法访问源代码,仍然可以使用以下方法调试一些崩溃转储(如Dave Miller的
示例崩溃转储输出所示)::
EIP is at +0x14/0x4c0
...
Code: 44 24 04 e8 6f 05 00 00 e9 e8 fe ff ff 8d 76 00 8d bc 27 00 00
00 00 55 57 56 53 81 ec bc 00 00 00 8b ac 24 d0 00 00 00 8b 5d 08
<8b> 83 3c 01 00 00 89 44 24 14 8b 45 28 85 c0 89 44 24 18 0f 85
Put the bytes into a "foo.s" file like this:
.text
.globl foo
foo:
.byte .... /* bytes from Code: part of OOPS dump */
Compile it with "gcc -c -o foo.o foo.s" then look at the output of
"objdump --disassemble foo.o".
Output:
ip_queue_xmit:
push %ebp
push %edi
push %esi
push %ebx
sub $0xbc, %esp
mov 0xd0(%esp), %ebp ! %ebp = arg0 (skb)
mov 0x8(%ebp), %ebx ! %ebx = skb->sk
mov 0x13c(%ebx), %eax ! %eax = inet_sk(sk)->opt
`scripts/decodecode` 文件可以用来自动完成大部分工作,这取决于正在调试的CPU
体系结构。
报告缺陷
---------
一旦你通过定位缺陷找到了其发生的地方,你可以尝试自己修复它或者向上游报告它。
为了向上游报告,您应该找出用于开发受影响代码的邮件列表。这可以使用 ``get_maintainer.pl`` 。
例如,您在gspca的sonixj.c文件中发现一个缺陷,则可以通过以下方法找到它的维护者::
$ ./scripts/get_maintainer.pl -f drivers/media/usb/gspca/sonixj.c
Hans Verkuil <hverkuil@kernel.org> (odd fixer:GSPCA USB WEBCAM DRIVER,commit_signer:1/1=100%)
Mauro Carvalho Chehab <mchehab@kernel.org> (maintainer:MEDIA INPUT INFRASTRUCTURE (V4L/DVB),commit_signer:1/1=100%)
Tejun Heo <tj@kernel.org> (commit_signer:1/1=100%)
Bhaktipriya Shridhar <bhaktipriya96@gmail.com> (commit_signer:1/1=100%,authored:1/1=100%,added_lines:4/4=100%,removed_lines:9/9=100%)
linux-media@vger.kernel.org (open list:GSPCA USB WEBCAM DRIVER)
linux-kernel@vger.kernel.org (open list)
请注意它将指出:
- 最后接触源代码的开发人员(如果这是在git树中完成的)。在上面的例子中是Tejun
和Bhaktipriya(在这个特定的案例中,没有人真正参与这个文件的开发);
- 驱动维护人员(Hans Verkuil);
- 子系统维护人员(Mauro Carvalho Chehab);
- 驱动程序和/或子系统邮件列表(linux-media@vger.kernel.org);
- Linux内核邮件列表(linux-kernel@vger.kernel.org)。
通常,修复缺陷的最快方法是将它报告给用于开发相关代码的邮件列表(linux-media
ML),抄送驱动程序维护者(Hans)。
如果你完全不知道该把报告寄给谁,且 ``get_maintainer.pl`` 也没有提供任何有用
的信息,请发送到linux-kernel@vger.kernel.org。
感谢您的帮助,这使Linux尽可能稳定:-)
修复缺陷
---------
如果你懂得编程,你不仅可以通过报告错误来帮助我们,还可以提供一个解决方案。
毕竟,开源就是分享你的工作,你不想因为你的天才而被认可吗?
如果你决定这样做,请在制定解决方案后将其提交到上游。
请务必阅读
:ref:`Documentation/process/submitting-patches.rst <submittingpatches>` ,
以帮助您的代码被接受。
---------------------------------------------------------------------------
用 ``klogd`` 进行Oops跟踪的注意事项
------------------------------------
为了帮助Linus和其他内核开发人员, ``klogd`` 对保护故障的处理提供了大量支持。
为了完整支持地址解析,至少应该使用 ``sysklogd`` 包的1.3-pl3版本。
当发生保护故障时, ``klogd`` 守护进程会自动将内核日志消息中的重要地址转换为
它们的等效符号。然后通过 ``klogd`` 使用的任何报告机制来转发这个已翻译的内核
消息。保护错误消息可以直接从消息文件中剪切出来并转发给内核开发人员。
``klogd`` 执行两种类型的地址解析,静态翻译和动态翻译。静态翻译使用System.map
文件。为了进行静态转换, ``klogd`` 守护进程必须能够在守护进程初始化时找到系
统映射文件。有关 ``klogd`` 如何搜索映射文件的信息,请参见klogd手册页。
当使用内核可加载模块时,动态地址转换非常重要。由于内核模块的内存是从内核的
动态内存池中分配的,因此无论是模块的开头还是模块中的函数和符号都没有固定的
位置。
内核支持系统调用,允许程序确定加载哪些模块及其在内存中的位置。klogd守护进程
使用这些系统调用构建了一个符号表,可用于调试可加载内核模块中发生的保护错误。
klogd至少会提供产生保护故障的模块的名称。如果可加载模块的开发人员选择从模块
导出符号信息,则可能会有其他可用的符号信息。
由于内核模块环境可以是动态的,因此当模块环境发生变化时,必须有一种通知
``klogd`` 守护进程的机制。有一些可用的命令行选项允许klogd向当前正在执行的守
护进程发出信号示意应该刷新符号信息。有关更多信息,请参阅 ``klogd`` 手册页。
sysklogd发行版附带了一个补丁,它修改了 ``modules-2.0.0`` 包,以便在加载或
卸载模块时自动向klogd发送信号。应用此补丁基本上可无缝支持调试内核可加载模块
发生的保护故障。
以下是 ``klogd`` 处理的可加载模块中的保护故障示例::
Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
Aug 29 09:51:01 blizard kernel: *pde = 00000000
Aug 29 09:51:01 blizard kernel: Oops: 0002
Aug 29 09:51:01 blizard kernel: CPU: 0
Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
@@ -0,0 +1,9 @@
清除 WARN_ONCE
--------------
WARN_ONCE / WARN_ON_ONCE / printk_once 仅仅打印一次消息.
echo 1 > /sys/kernel/debug/clear_warn_once
可以清除这种状态并且再次允许打印一次告警信息,这对于运行测试集后重现问题
很有用。
@@ -0,0 +1,105 @@
========
CPU 负载
========
Linux通过``/proc/stat``和``/proc/uptime``导出各种信息,用户空间工具
如top(1)使用这些信息计算系统花费在某个特定状态的平均时间。
例如:
$ iostat
Linux 2.6.18.3-exp (linmac) 02/20/2007
avg-cpu: %user %nice %system %iowait %steal %idle
10.01 0.00 2.92 5.44 0.00 81.63
...
这里系统认为在默认采样周期內有10.01%的时间工作在用户空间,2.92%的时
间用在系统空间,总体上有81.63%的时间是空闲的。
大多数情况下``/proc/stat``的信息几乎真实反映了系统信息,然而,由于内
核采集这些数据的方式/时间的特点,有时这些信息根本不可靠。
那么这些信息是如何被搜集的呢?每当时间中断触发时,内核查看此刻运行的
进程类型,并增加与此类型/状态进程对应的计数器的值。这种方法的问题是
在两次时间中断之间系统(进程)能够在多种状态之间切换多次,而计数器只
增加最后一种状态下的计数。
举例
---
假设系统有一个进程以如下方式周期性地占用cpu::
两个时钟中断之间的时间线
|-----------------------|
^ ^
|_ 开始运行 |
|_ 开始睡眠
(很快会被唤醒)
在上面的情况下,根据``/proc/stat``的信息(由于当系统处于空闲状态时,
时间中断经常会发生)系统的负载将会是0
大家能够想象内核的这种行为会发生在许多情况下,这将导致``/proc/stat``
中存在相当古怪的信息::
/* gcc -o hog smallhog.c */
#include <time.h>
#include <limits.h>
#include <signal.h>
#include <sys/time.h>
#define HIST 10
static volatile sig_atomic_t stop;
static void sighandler (int signr)
{
(void) signr;
stop = 1;
}
static unsigned long hog (unsigned long niters)
{
stop = 0;
while (!stop && --niters);
return niters;
}
int main (void)
{
int i;
struct itimerval it = { .it_interval = { .tv_sec = 0, .tv_usec = 1 },
.it_value = { .tv_sec = 0, .tv_usec = 1 } };
sigset_t set;
unsigned long v[HIST];
double tmp = 0.0;
unsigned long n;
signal (SIGALRM, &sighandler);
setitimer (ITIMER_REAL, &it, NULL);
hog (ULONG_MAX);
for (i = 0; i < HIST; ++i) v[i] = ULONG_MAX - hog (ULONG_MAX);
for (i = 0; i < HIST; ++i) tmp += v[i];
tmp /= HIST;
n = tmp - (tmp / 3.0);
sigemptyset (&set);
sigaddset (&set, SIGALRM);
for (;;) {
hog (n);
sigwait (&set, &i);
}
return 0;
}
参考
---
- https://lore.kernel.org/r/loom.20070212T063225-663@post.gmane.org
- Documentation/filesystems/proc.rst (1.8)
谢谢
---
Con Kolivas, Pavel Machek
@@ -0,0 +1,96 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/cputopology.rst
:翻译:
唐艺舟 Tang Yizhou <tangyeechou@gmail.com>
==========================
如何通过sysfs将CPU拓扑导出
==========================
CPU拓扑信息通过sysfs导出。显示的项(属性)和某些架构的/proc/cpuinfo输出相似。它们位于
/sys/devices/system/cpu/cpuX/topology/。请阅读ABI文件:
Documentation/ABI/stable/sysfs-devices-system-cpu。
drivers/base/topology.c是体系结构中性的,它导出了这些属性。然而,die、cluster、book、
draw这些层次结构相关的文件仅在体系结构提供了下文描述的宏的条件下被创建。
对于支持这个特性的体系结构,它必须在include/asm-XXX/topology.h中定义这些宏中的一部分::
#define topology_physical_package_id(cpu)
#define topology_die_id(cpu)
#define topology_cluster_id(cpu)
#define topology_core_id(cpu)
#define topology_book_id(cpu)
#define topology_drawer_id(cpu)
#define topology_sibling_cpumask(cpu)
#define topology_core_cpumask(cpu)
#define topology_cluster_cpumask(cpu)
#define topology_die_cpumask(cpu)
#define topology_book_cpumask(cpu)
#define topology_drawer_cpumask(cpu)
``**_id macros`` 的类型是int。
``**_cpumask macros`` 的类型是 ``(const) struct cpumask *`` 。后者和恰当的
``**_siblings`` sysfs属性对应(除了topology_sibling_cpumask(),它和thread_siblings
对应)。
为了在所有体系结构上保持一致,include/linux/topology.h提供了上述所有宏的默认定义,以防
它们未在include/asm-XXX/topology.h中定义:
1) topology_physical_package_id: -1
2) topology_die_id: -1
3) topology_cluster_id: -1
4) topology_core_id: 0
5) topology_book_id: -1
6) topology_drawer_id: -1
7) topology_sibling_cpumask: 仅入参CPU
8) topology_core_cpumask: 仅入参CPU
9) topology_cluster_cpumask: 仅入参CPU
10) topology_die_cpumask: 仅入参CPU
11) topology_book_cpumask: 仅入参CPU
12) topology_drawer_cpumask: 仅入参CPU
此外,CPU拓扑信息由/sys/devices/system/cpu提供,包含下述文件。输出对应的内部数据源放在
方括号("[]")中。
=========== ==================================================================
kernel_max: 内核配置允许的最大CPU下标值。[NR_CPUS-1]
offline: 由于热插拔移除或者超过内核允许的CPU上限(上文描述的kernel_max)
导致未上线的CPU。[~cpu_online_mask + cpus >= NR_CPUS]
online: 在线的CPU,可供调度使用。[cpu_online_mask]
possible: 已被分配资源的CPU,如果它们CPU实际存在,可以上线。
[cpu_possible_mask]
present: 被系统识别实际存在的CPU。[cpu_present_mask]
=========== ==================================================================
上述输出的格式和cpulist_parse()兼容[参见 <linux/cpumask.h>]。下面给些例子。
在本例中,系统中有64个CPU,但是CPU 32-63超过了kernel_max值,因为NR_CPUS配置项是32,
取值范围被限制为0..31。此外注意CPU2和4-31未上线,但是可以上线,因为它们同时存在于
present和possible::
kernel_max: 31
offline: 2,4-31,32-63
online: 0-1,3
possible: 0-31
present: 0-31
在本例中,NR_CPUS配置项是128,但内核启动时设置possible_cpus=144。系统中有4个CPU,
CPU2被手动设置下线(也是唯一一个可以上线的CPU)::
kernel_max: 127
offline: 2,4-127,128-143
online: 0-1,3
possible: 0-127
present: 0-3
阅读Documentation/core-api/cpu_hotplug.rst可了解开机参数possible_cpus=NUM,同时还
可以了解各种cpumask的信息。
@@ -0,0 +1,132 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :doc:`../../../admin-guide/index`
:Translator: Alex Shi <alex.shi@linux.alibaba.com>
Linux 内核用户和管理员指南
==========================
下面是一组随时间添加到内核中的面向用户的文档的集合。到目前为止,还没有一个
整体的顺序或组织 - 这些材料不是一个单一的,连贯的文件!幸运的话,情况会随着
时间的推移而迅速改善。
这个初始部分包含总体信息,包括描述内核的README, 关于内核参数的文档等。
.. toctree::
:maxdepth: 1
README
Todolist:
* kernel-parameters
* devices
* sysctl/index
本节介绍CPU漏洞及其缓解措施。
Todolist:
* hw-vuln/index
下面的一组文档,针对的是试图跟踪问题和bug的用户。
.. toctree::
:maxdepth: 1
reporting-issues
reporting-regressions
bug-hunting
bug-bisect
tainted-kernels
init
Todolist:
* ramoops
* dynamic-debug-howto
* kdump/index
* perf/index
这是应用程序开发人员感兴趣的章节的开始。可以在这里找到涵盖内核ABI各个
方面的文档。
Todolist:
* sysfs-rules
本手册的其余部分包括各种指南,介绍如何根据您的喜好配置内核的特定行为。
.. toctree::
:maxdepth: 1
bootconfig
clearing-warn-once
cpu-load
cputopology
lockup-watchdogs
numastat
unicode
sysrq
mm/index
Todolist:
* acpi/index
* aoe/index
* auxdisplay/index
* bcache
* binderfs
* binfmt-misc
* blockdev/index
* braille-console
* btmrvl
* cgroup-v1/index
* cgroup-v2
* cifs/index
* dell_rbu
* device-mapper/index
* edid
* efi-stub
* ext4
* nfs/index
* gpio/index
* highuid
* hw_random
* initrd
* iostats
* java
* jfs
* kernel-per-CPU-kthreads
* laptops/index
* lcd-panel-cgram
* ldm
* LSM/index
* md
* media/index
* module-signing
* mono
* namespaces/index
* parport
* perf-security
* pm/index
* pnp
* rapidio
* ras
* rtc
* serial-console
* svga
* thunderbolt
* ufs
* vga-softcursor
* video-output
* xfs
.. only:: subproject and html
Indices
=======
* :ref:`genindex`
@@ -0,0 +1,54 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: :doc:`../../../admin-guide/init`
:译者:
吴想成 Wu XiangCheng <bobwxc@email.cn>
解释“No working init found.”启动挂起消息
=========================================
:作者:
Andreas Mohr <andi at lisas period de>
Cristian Souza <cristianmsbr at gmail period com>
本文档提供了加载初始化二进制(init binary)失败的一些高层级原因(大致按执行
顺序列出)。
1) **无法挂载根文件系统Unable to mount root FS** :请设置“debug”内核参数(在
引导加载程序bootloader配置文件或CONFIG_CMDLINE)以获取更详细的内核消息。
2) **初始化二进制不存在于根文件系统上init binary doesn't exist on rootfs** :
确保您的根文件系统类型正确(并且 ``root=`` 内核参数指向正确的分区);拥有
所需的驱动程序,例如SCSI或USB等存储硬件;文件系统(ext3、jffs2等)是内建的
(或者作为模块由initrd预加载)。
3) **控制台设备损坏Broken console device** : ``console= setup`` 中可能存在
冲突 --> 初始控制台不可用(initial console unavailable)。例如,由于串行
IRQ问题(如缺少基于中断的配置)导致的某些串行控制台不可靠。尝试使用不同的
``console= device`` 或像 ``netconsole=`` 。
4) **二进制存在但依赖项不可用Binary exists but dependencies not available** :
例如初始化二进制的必需库依赖项,像 ``/lib/ld-linux.so.2`` 丢失或损坏。使用
``readelf -d <INIT>|grep NEEDED`` 找出需要哪些库。
5) **无法加载二进制Binary cannot be loaded** :请确保二进制的体系结构与您的
硬件匹配。例如i386不匹配x86_64,或者尝试在ARM硬件上加载x86。如果您尝试在
此处加载非二进制文件(shell脚本?),您应该确保脚本在其工作头(shebang
header)行 ``#!/...`` 中指定能正常工作的解释器(包括其库依赖项)。在处理
脚本之前,最好先测试一个简单的非脚本二进制文件,比如 ``/bin/sh`` ,并确认
它能成功执行。要了解更多信息,请将代码添加到 ``init/main.c`` 以显示
kernel_execve()的返回值。
当您发现新的失败原因时,请扩展本解释(毕竟加载初始化二进制是一个 **关键** 且
艰难的过渡步骤,需要尽可能无痛地进行),然后向LKML提交一个补丁。
待办事项:
- 通过一个可以存储 ``kernel_execve()`` 结果值的结构体数组实现各种
``run_init_process()`` 调用,并在失败时通过迭代 **所有** 结果来记录一切
(非常重要的可用性修复)。
- 试着使实现本身在一般情况下更有帮助,例如在受影响的地方提供额外的错误消息。
@@ -0,0 +1,66 @@
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/lockup-watchdogs.rst
:Translator: Hailong Liu <liu.hailong6@zte.com.cn>
.. _cn_lockup-watchdogs:
=================================================
Softlockup与hardlockup检测机制(又名:nmi_watchdog)
=================================================
Linux中内核实现了一种用以检测系统发生softlockup和hardlockup的看门狗机制。
Softlockup是一种会引发系统在内核态中一直循环超过20秒(详见下面“实现”小节)导致
其他任务没有机会得到运行的BUG。一旦检测到'softlockup'发生,默认情况下系统会打
印当前堆栈跟踪信息并进入锁定状态。也可配置使其在检测到'softlockup'后进入panic
状态;通过sysctl命令设置“kernel.softlockup_panic”、使用内核启动参数
“softlockup_panic”(详见Documentation/admin-guide/kernel-parameters.rst)以及使
能内核编译选项“BOOTPARAM_SOFTLOCKUP_PANIC”都可实现这种配置。
而'hardlockup'是一种会引发系统在内核态一直循环超过10秒钟(详见"实现"小节)导致其
他中断没有机会运行的缺陷。与'softlockup'情况类似,除了使用sysctl命令设置
'hardlockup_panic'、使能内核选项“BOOTPARAM_HARDLOCKUP_PANIC”以及使用内核参数
"nmi_watchdog"(详见:”Documentation/admin-guide/kernel-parameters.rst“)外,一旦检
测到'hardlockup'默认情况下系统打印当前堆栈跟踪信息,然后进入锁定状态。
这个panic选项也可以与panic_timeout结合使用(这个panic_timeout是通过稍具迷惑性的
sysctl命令"kernel.panic"来设置),使系统在panic指定时间后自动重启。
实现
====
Softlockup和hardlockup分别建立在hrtimer(高精度定时器)和perf两个子系统上而实现。
这也就意味着理论上任何架构只要实现了这两个子系统就支持这两种检测机制。
Hrtimer用于周期性产生中断并唤醒watchdog线程;NMI perf事件则以”watchdog_thresh“
(编译时默认初始化为10秒,也可通过”watchdog_thresh“这个sysctl接口来进行配置修改)
为间隔周期产生以检测 hardlockups。如果一个CPU在这个时间段内没有检测到hrtimer中
断发生,'hardlockup 检测器'(即NMI perf事件处理函数)将会视系统配置而选择产生内核
警告或者直接panic。
而watchdog线程本质上是一个高优先级内核线程,每调度一次就对时间戳进行一次更新。
如果时间戳在2*watchdog_thresh(这个是softlockup的触发门限)这段时间都未更新,那么
"softlocup 检测器"(内部hrtimer定时器回调函数)会将相关的调试信息打印到系统日志中,
然后如果系统配置了进入panic流程则进入panic,否则内核继续执行。
Hrtimer定时器的周期是2*watchdog_thresh/5,也就是说在hardlockup被触发前hrtimer有
2~3次机会产生时钟中断。
如上所述,内核相当于为系统管理员提供了一个可调节hrtimer定时器和perf事件周期长度
的调节旋钮。如何通过这个旋钮为特定使用场景配置一个合理的周期值要对lockups检测的
响应速度和lockups检测开销这二者之间进行权衡。
默认情况下所有在线cpu上都会运行一个watchdog线程。不过在内核配置了”NO_HZ_FULL“的
情况下watchdog线程默认只会运行在管家(housekeeping)cpu上,而”nohz_full“启动参数指
定的cpu上则不会有watchdog线程运行。试想,如果我们允许watchdog线程在”nohz_full“指
定的cpu上运行,这些cpu上必须得运行时钟定时器来激发watchdog线程调度;这样一来就会
使”nohz_full“保护用户程序免受内核干扰的功能失效。当然,副作用就是”nohz_full“指定
的cpu即使在内核产生了lockup问题我们也无法检测到。不过,至少我们可以允许watchdog
线程在管家(non-tickless)核上继续运行以便我们能继续正常的监测这些cpus上的lockups
事件。
不论哪种情况都可以通过sysctl命令kernel.watchdog_cpumask来对没有运行watchdog线程
的cpu集合进行调节。对于nohz_full而言,如果nohz_full cpu上有异常挂住的情况,通过
这种方式打开这些cpu上的watchdog进行调试可能会有所作用。
@@ -0,0 +1,29 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/index.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
============
监测数据访问
============
:doc:`DAMON </mm/damon/index>` 允许轻量级的数据访问监测。使用DAMON,
用户可以分析他们系统的内存访问模式,并优化它们。
.. toctree::
:maxdepth: 2
start
usage
reclaim
lru_sort
@@ -0,0 +1,263 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/lru_sort.rst
:翻译:
臧雷刚 Leigang Zang <zangleigang@hisilicon.com>
:校译:
==================
基于DAMON的LRU排序
==================
基于DAMON的LRU排序是一个静态的内核模块,旨在用于以主动的、轻量级的数据访问模型
为基础的页面优先级处理的LRU链表上,以使得LRU上的数据访问模型更为可信。
哪里需要主动的LRU排序
=====================
在一个大型系统中,以页为粒度的访问检测会有比较显著的开销,LRU通常不会主动去排序,
而是对部分特殊事件进行部分的、响应式的排序,例如:特殊的用户请求,系统调用或者
内存压力。这导致,在有些场景下,LRU不能够完美的作为一个可信的数据访问模型,比如
在内存压力下对目标内存进行回收。
因为DAMON能够尽可能准确的识别数据访问模型,同时只引起用户指定范围的开销,主动的
执行DAMON_LRU_SORT让LRU变得更为可信是有益的,而且这只需要较少和可控的开销。
这是如何工作的
==============
DAMON_LRU_SORT使用DAMON寻找热页(范围内的页面访问频率高于用户指定的阈值)和冷页
(范围内的页面在超过用户指定的时间无访问),并提高热页和降低冷页在LRU中的优先级。
为了避免在排序过程占用更多的CPU计算资源,可以设置一个CPU占用时间的约束值。在约
束下,分别提升或者降低更多的热页和冷页。系统管理员也可以配置三个内存水位以控制
在何种条件下自动激活或者停止这种机制。
冷热阈值和CPU约束的默认值是比较保守的。这意味着,在默认参数下,模块可以广泛且无
负作用的使用在常见环境中,同时在只消耗一小部分CPU时间的情况下,给有内存压力的系
统提供一定水平的冷热识别。
接口:模块参数
==============
使用此特性,你首先需要确认你的系统中运行的内核在编译时启用了
``CONFIG_DAMON_LRU_SORT=y``.
为了让系统管理员打开或者关闭并且调节指定的系统,DAMON_LRU_SORT设计了模块参数。
这意味着,你可以添加 ``damon_lru_sort.<parameter>=<value>`` 到内核的启动命令行
参数,或者在 ``/sys/modules/damon_lru_sort/parameters/<parameter>`` 写入正确的
值。
下边是每个参数的描述
enabled
-------
打开或者关闭DAMON_LRU_SORT.
你可以通过设置这个参数为 ``Y`` 来打开DAMON_LRU_SORT。设置为 ``N`` 关闭
DAMON_LRU_SORT。注意,在基于水位的激活的情况下,DAMON_LRU_SORT有可能不会真正去
监测或者做LRU排序。对这种情况,参考下方关于水位的描述。
commit_inputs
-------------
让DAMON_LRU_SORT再次读取输入参数,除了 ``enabled`` 。
在DAMON_LRU_SORT运行时,新的输入参数默认不会被应用。一旦这个参数被设置为 ``Y``
,DAMON_LRU_SORT会再次读取除了 ``enabled`` 之外的参数。读取完成后,这个参数会被
设置为 ``N`` 。如果在读取时发现有无效参数,DAMON_LRU_SORT会被关闭。
hot_thres_access_freq
---------------------
热点内存区域的访问频率阈值,千分比。
如果一个内存区域的访问频率大于等于这个值,DAMON_LRU_SORT把这个区域看作热区,并
在LRU上把这个区域标记为已访问,因些在内存压力下这部分内存不会被回收。默认为50%。
cold_min_age
------------
用于识别冷内存区域的时间阈值,单位是微秒。
如果一个内存区域在这个时间内未被访问过,DAMON_LRU_SORT把这个区域看作冷区,并在
LRU上把这个区域标记为未访问,因此在内存压力下这些内存会首先被回收。默认值为120
秒。
quota_ms
--------
尝试LRU链表排序的时间限制,单位是毫秒。
DAMON_LRU_SORT在一个时间窗口内(quota_reset_interval_ms)内最多尝试这么长时间来
对LRU进行排序。这个可以用来作为CPU计算资源的约束。如果值为0,则表示无限制。
默认10毫秒。
quota_reset_interval_ms
-----------------------
配额计时重置周期,毫秒。
配额计时重置周期。即,在quota_reset_interval_ms毫秒内,DAMON_LRU_SORT对LRU进行
排序不会超过quota_ms或者quota_sz。
默认1秒。
wmarks_interval
---------------
水位的检查周期,单位是微秒。
当DAMON_LRU_SORT使能但是由于水位而不活跃时检查水位前最小的等待时间。默认值5秒。
wmarks_high
-----------
空闲内存高水位,千分比。
如果空闲内存水位高于这个值,DAMON_LRU_SORT停止工作,不做任何事,除了周期性的检
查水位。默认200(20%)。
wmarks_mid
----------
空闲内存中间水位,千分比。
如果空闲内存水位在这个值与低水位之间,DAMON_LRU_SORT开始工作,开始检测并对LRU链
表进行排序。默认150(15%)。
wmarks_low
----------
空闲内存低水位,千分比。
如果空闲内存小于这个值,DAMON_LRU_SORT不再工作,不做任何事,除了周期性的检查水
线。默认50(5%)。
sample_interval
---------------
监测的采样周期,微秒。
DAMON对冷内存监测的采样周期。更多细节请参考DAMON文档 (:doc:`usage`) 。默认5
毫秒。
aggr_interval
-------------
监测的收集周期,微秒。
DAMON对冷内存进行收集的时间周期。更多细节请参考DAMON文档 (:doc:`usage`) 。默认
100毫秒。
min_nr_regions
--------------
最小监测区域数量。
对冷内存区域监测的最小数量。这个值可以作为监测质量的下限。不过,这个值设置的过
大会增加开销。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为10。
max_nr_regions
--------------
最大监测区域数量。
对冷内存区域监测的最大数量。这个值可以作为监测质量的上限。然而,这个值设置的过
低会导致监测结果变差。更多细节请参考DAMON文档 (:doc:`usage`) 。默认值为1000。
monitor_region_start
--------------------
目标内存区域的起始物理地址。
DAMON_LRU_SORT要处理的目标内存区域的起始物理地址。默认,使用系统最大内存。
monitor_region_end
------------------
目标内存区域的结束物理地址。
DAMON_LRU_SORT要处理的目标内存区域的结束物理地址。默认,使用系统最大内存。
kdamond_pid
-----------
DAMON线程的PID。
如果DAMON_LRU_SORT是使能的,这个表示任务线程的PID。其它情况为-1。
nr_lru_sort_tried_hot_regions
-----------------------------
被尝试进行LRU排序的热内存区域的数量。
bytes_lru_sort_tried_hot_regions
--------------------------------
被尝试进行LRU排序的热内存区域的大小(字节)。
nr_lru_sorted_hot_regions
-------------------------
成功进行LRU排序的热内存区域的数量。
bytes_lru_sorted_hot_regions
----------------------------
成功进行LRU排序的热内存区域的大小(字节)。
nr_hot_quota_exceeds
--------------------
热区域时间约束超过限制的次数。
nr_lru_sort_tried_cold_regions
------------------------------
被尝试进行LRU排序的冷内存区域的数量。
bytes_lru_sort_tried_cold_regions
---------------------------------
被尝试进行LRU排序的冷内存区域的大小(字节)。
nr_lru_sorted_cold_regions
--------------------------
成功进行LRU排序的冷内存区域的数量。
bytes_lru_sorted_cold_regions
-----------------------------
成功进行LRU排序的冷内存区域的大小(字节)。
nr_cold_quota_exceeds
---------------------
冷区域时间约束超过限制的次数。
Example
=======
如下是一个运行时的命令示例,使DAMON_LRU_SORT查找访问频率超过50%的区域并对其进行
LRU的优先级的提升,同时降低那些超过120秒无人访问的内存区域的优先级。优先级的处
理被限制在最多1%的CPU以避免DAMON_LRU_SORT消费过多CPU时间。在系统空闲内存超过50%
时DAMON_LRU_SORT停止工作,并在低于40%时重新开始工作。如果DAMON_RECLAIM没有取得
进展且空闲内存低于20%,再次让DAMON_LRU_SORT停止工作,以此回退到以LRU链表为基础
以页面为单位的内存回收上。 ::
# cd /sys/modules/damon_lru_sort/parameters
# echo 500 > hot_thres_access_freq
# echo 120000000 > cold_min_age
# echo 10 > quota_ms
# echo 1000 > quota_reset_interval_ms
# echo 500 > wmarks_high
# echo 400 > wmarks_mid
# echo 200 > wmarks_low
# echo Y > enabled
@@ -0,0 +1,228 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/reclaim.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
===============
基于DAMON的回收
===============
基于DAMON的回收(DAMON_RECLAIM)是一个静态的内核模块,旨在用于轻度内存压力下的主动和轻
量级的回收。它的目的不是取代基于LRU列表的页面回收,而是有选择地用于不同程度的内存压力和要
求。
哪些地方需要主动回收?
======================
在一般的内存超量使用(over-committed systems,虚拟化相关术语)的系统上,主动回收冷页
有助于节省内存和减少延迟高峰,这些延迟是由直接回收进程或kswapd的CPU消耗引起的,同时只产
生最小的性能下降 [1]_ [2]_ 。
基于空闲页报告 [3]_ 的内存过度承诺的虚拟化系统就是很好的例子。在这样的系统中,客户机
向主机报告他们的空闲内存,而主机则将报告的内存重新分配给其他客户。因此,系统的内存得到了充
分的利用。然而,客户可能不那么节省内存,主要是因为一些内核子系统和用户空间应用程序被设计为
使用尽可能多的内存。然后,客户机可能只向主机报告少量的内存是空闲的,导致系统的内存利用率下降。
在客户中运行主动回收可以缓解这个问题。
它是如何工作的?
================
DAMON_RECLAIM找到在特定时间内没有被访问的内存区域并分页。为了避免它在分页操作中消耗过多
的CPU,可以配置一个速度限制。在这个速度限制下,它首先分页出那些没有被访问过的内存区域。系
统管理员还可以配置在什么情况下这个方案应该自动激活和停用三个内存压力水位。
接口: 模块参数
==============
要使用这个功能,你首先要确保你的系统运行在一个以 ``CONFIG_DAMON_RECLAIM=y`` 构建的内
核上。
为了让系统管理员启用或禁用它,并为给定的系统进行调整,DAMON_RECLAIM利用了模块参数。也就
是说,你可以把 ``damon_reclaim.<parameter>=<value>`` 放在内核启动命令行上,或者把
适当的值写入 ``/sys/module/damon_reclaim/parameters/<parameter>`` 文件。
下面是每个参数的描述。
enabled
-------
启用或禁用DAMON_RECLAIM。
你可以通过把这个参数的值设置为 ``Y`` 来启用DAMON_RCLAIM,把它设置为 ``N`` 可以禁用
DAMON_RECLAIM。注意,由于基于水位的激活条件,DAMON_RECLAIM不能进行真正的监测和回收。
这一点请参考下面关于水位参数的描述。
min_age
-------
识别冷内存区域的时间阈值,单位是微秒。
如果一个内存区域在这个时间或更长的时间内没有被访问,DAMON_RECLAIM会将该区域识别为冷的,
并回收它。
默认为120秒。
quota_ms
--------
回收的时间限制,以毫秒为单位。
DAMON_RECLAIM 试图在一个时间窗口(quota_reset_interval_ms)内只使用到这个时间,以
尝试回收冷页。这可以用来限制DAMON_RECLAIM的CPU消耗。如果该值为零,则该限制被禁用。
默认为10ms。
quota_sz
--------
回收的内存大小限制,单位为字节。
DAMON_RECLAIM 收取在一个时间窗口(quota_reset_interval_ms)内试图回收的内存量,并
使其不超过这个限制。这可以用来限制CPU和IO的消耗。如果该值为零,则限制被禁用。
默认情况下是128 MiB。
quota_reset_interval_ms
-----------------------
时间/大小配额收取重置间隔,单位为毫秒。
时间(quota_ms)和大小(quota_sz)的配额的目标重置间隔。也就是说,DAMON_RECLAIM在
尝试回收‘不’超过quota_ms毫秒或quota_sz字节的内存。
默认为1秒。
wmarks_interval
---------------
当DAMON_RECLAIM被启用但由于其水位规则而不活跃时,在检查水位之前的最小等待时间。
wmarks_high
-----------
高水位的可用内存率(每千字节)。
如果系统的可用内存(以每千字节为单位)高于这个数值,DAMON_RECLAIM就会变得不活跃,所以
它什么也不做,只是定期检查水位。
wmarks_mid
----------
中间水位的可用内存率(每千字节)。
如果系统的空闲内存(以每千字节为单位)在这个和低水位线之间,DAMON_RECLAIM就会被激活,
因此开始监测和回收。
wmarks_low
----------
低水位的可用内存率(每千字节)。
如果系统的空闲内存(以每千字节为单位)低于这个数值,DAMON_RECLAIM就会变得不活跃,所以
它除了定期检查水位外什么都不做。在这种情况下,系统会退回到基于LRU列表的页面粒度回收逻辑。
sample_interval
---------------
监测的采样间隔,单位是微秒。
DAMON用于监测冷内存的采样间隔。更多细节请参考DAMON文档 (:doc:`usage`) 。
aggr_interval
-------------
监测的聚集间隔,单位是微秒。
DAMON对冷内存监测的聚集间隔。更多细节请参考DAMON文档 (:doc:`usage`)。
min_nr_regions
--------------
监测区域的最小数量。
DAMON用于冷内存监测的最小监测区域数。这可以用来设置监测质量的下限。但是,设
置的太高可能会导致监测开销的增加。更多细节请参考DAMON文档 (:doc:`usage`) 。
max_nr_regions
--------------
监测区域的最大数量。
DAMON用于冷内存监测的最大监测区域数。这可以用来设置监测开销的上限值。但是,
设置得太低可能会导致监测质量不好。更多细节请参考DAMON文档 (:doc:`usage`) 。
monitor_region_start
--------------------
目标内存区域的物理地址起点。
DAMON_RECLAIM将对其进行工作的内存区域的起始物理地址。也就是说,DAMON_RECLAIM
将在这个区域中找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
monitor_region_end
------------------
目标内存区域的结束物理地址。
DAMON_RECLAIM将对其进行工作的内存区域的末端物理地址。也就是说,DAMON_RECLAIM将
在这个区域内找到冷的内存区域并进行回收。默认情况下,该区域使用最大系统内存区。
kdamond_pid
-----------
DAMON线程的PID。
如果DAMON_RECLAIM被启用,这将成为工作线程的PID。否则,为-1。
nr_reclaim_tried_regions
------------------------
试图通过DAMON_RECLAIM回收的内存区域的数量。
bytes_reclaim_tried_regions
---------------------------
试图通过DAMON_RECLAIM回收的内存区域的总字节数。
nr_reclaimed_regions
--------------------
通过DAMON_RECLAIM成功回收的内存区域的数量。
bytes_reclaimed_regions
-----------------------
通过DAMON_RECLAIM成功回收的内存区域的总字节数。
nr_quota_exceeds
----------------
超过时间/空间配额限制的次数。
例子
====
下面的运行示例命令使DAMON_RECLAIM找到30秒或更长时间没有访问的内存区域并“回收”?
为了避免DAMON_RECLAIM在分页操作中消耗过多的CPU时间,回收被限制在每秒1GiB以内。
它还要求DAMON_RECLAIM在系统的可用内存率超过50%时不做任何事情,但如果它低于40%时
就开始真正的工作。如果DAMON_RECLAIM没有取得进展,因此空闲内存率低于20%,它会要求
DAMON_RECLAIM再次什么都不做,这样我们就可以退回到基于LRU列表的页面粒度回收了::
# cd /sys/module/damon_reclaim/parameters
# echo 30000000 > min_age
# echo $((1 * 1024 * 1024 * 1024)) > quota_sz
# echo 1000 > quota_reset_interval_ms
# echo 500 > wmarks_high
# echo 400 > wmarks_mid
# echo 200 > wmarks_low
# echo Y > enabled
.. [1] https://research.google/pubs/pub48551/
.. [2] https://lwn.net/Articles/787611/
.. [3] https://www.kernel.org/doc/html/latest/mm/free_page_reporting.html
@@ -0,0 +1,124 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../../../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/mm/damon/start.rst
:翻译:
司延腾 Yanteng Si <siyanteng@loongson.cn>
:校译:
========
入门指南
========
本文通过演示DAMON的默认用户空间工具,简要地介绍了如何使用DAMON。请注意,为了简洁
起见,本文档只描述了它的部分功能。更多细节请参考该工具的使用文档。
`doc <https://github.com/damonitor/damo/blob/next/USAGE.md>`_ .
前提条件
========
内核
----
首先,你要确保你当前系统中跑的内核构建时选定了这个功能选项 ``CONFIG_DAMON_*=y``.
用户空间工具
------------
在演示中,我们将使用DAMON的默认用户空间工具,称为DAMON Operator(DAMO)。它可以在
https://github.com/damonitor/damo找到。下面的例子假设DAMO在你的$PATH上。当然,但
这并不是强制性的。
因为DAMO使用了DAMON的sysfs接口(详情请参考:doc:`usage`),你应该确保
:doc:`sysfs </filesystems/sysfs>` 被挂载。
记录数据访问模式
================
下面的命令记录了一个程序的内存访问模式,并将监测结果保存到文件中。 ::
$ git clone https://github.com/sjp38/masim
$ cd masim; make; ./masim ./configs/zigzag.cfg &
$ sudo damo record -o damon.data $(pidof masim)
命令的前两行下载了一个人工内存访问生成器程序并在后台运行。生成器将重复地逐一访问两个
100 MiB大小的内存区域。你可以用你的真实工作负载来代替它。最后一行要求 ``damo`` 将
访问模式记录在 ``damon.data`` 文件中。
将记录的模式可视化
==================
你可以在heatmap中直观地看到这种模式,显示哪个内存区域(X轴)何时被访问(Y轴)以及访
问的频率(数字)。::
$ sudo damo report heats --heatmap stdout
22222222222222222222222222222222222222211111111111111111111111111111111111111100
44444444444444444444444444444444444444434444444444444444444444444444444444443200
44444444444444444444444444444444444444433444444444444444444444444444444444444200
33333333333333333333333333333333333333344555555555555555555555555555555555555200
33333333333333333333333333333333333344444444444444444444444444444444444444444200
22222222222222222222222222222222222223355555555555555555555555555555555555555200
00000000000000000000000000000000000000288888888888888888888888888888888888888400
00000000000000000000000000000000000000288888888888888888888888888888888888888400
33333333333333333333333333333333333333355555555555555555555555555555555555555200
88888888888888888888888888888888888888600000000000000000000000000000000000000000
88888888888888888888888888888888888888600000000000000000000000000000000000000000
33333333333333333333333333333333333333444444444444444444444444444444444444443200
00000000000000000000000000000000000000288888888888888888888888888888888888888400
[...]
# access_frequency: 0 1 2 3 4 5 6 7 8 9
# x-axis: space (139728247021568-139728453431248: 196.848 MiB)
# y-axis: time (15256597248362-15326899978162: 1 m 10.303 s)
# resolution: 80x40 (2.461 MiB and 1.758 s for each character)
你也可以直观地看到工作集的大小分布,按大小排序。::
$ sudo damo report wss --range 0 101 10
# <percentile> <wss>
# target_id 18446632103789443072
# avr: 107.708 MiB
0 0 B | |
10 95.328 MiB |**************************** |
20 95.332 MiB |**************************** |
30 95.340 MiB |**************************** |
40 95.387 MiB |**************************** |
50 95.387 MiB |**************************** |
60 95.398 MiB |**************************** |
70 95.398 MiB |**************************** |
80 95.504 MiB |**************************** |
90 190.703 MiB |********************************************************* |
100 196.875 MiB |***********************************************************|
在上述命令中使用 ``--sortby`` 选项,可以显示工作集的大小是如何按时间顺序变化的。::
$ sudo damo report wss --range 0 101 10 --sortby time
# <percentile> <wss>
# target_id 18446632103789443072
# avr: 107.708 MiB
0 3.051 MiB | |
10 190.703 MiB |***********************************************************|
20 95.336 MiB |***************************** |
30 95.328 MiB |***************************** |
40 95.387 MiB |***************************** |
50 95.332 MiB |***************************** |
60 95.320 MiB |***************************** |
70 95.398 MiB |***************************** |
80 95.398 MiB |***************************** |
90 95.340 MiB |***************************** |
100 95.398 MiB |***************************** |
数据访问模式感知的内存管理
==========================
以下三个命令使每一个大小>=4K的内存区域在你的工作负载中没有被访问>=60秒,就会被换掉。 ::
$ echo "#min-size max-size min-acc max-acc min-age max-age action" > test_scheme
$ echo "4K max 0 0 60s max pageout" >> test_scheme
$ damo schemes -c test_scheme <pid of your workload>
@@ -0,0 +1,345 @@
.. 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/damonitor/damo>`_ 为有这特权的人, 如系统管理员,希望有一个刚好
可以工作的人性化界面。
使用它,用户可以以人性化的方式使用DAMON的主要功能。不过,它可能不会为特殊情况进行高度调整。
它同时支持虚拟和物理地址空间的监测。更多细节,请参考它的 `使用文档
<https://github.com/damonitor/damo/blob/next/USAGE.md>`_。
- *sysfs接口。*
:ref:`这 <sysfs_interface>` 是为那些希望更高级的使用DAMON的特权用户空间程序员准备的。
使用它,用户可以通过读取和写入特殊的sysfs文件来使用DAMON的主要功能。因此,你可以编写和使
用你个性化的DAMON sysfs包装程序,代替你读/写sysfs文件。 `DAMON用户空间工具
<https://github.com/damonitor/damo>`_ 就是这种程序的一个例子 它同时支持虚拟和物理地址
空间的监测。
- *内核空间编程接口。*
: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_kdamonds && echo 1 > kdamonds/0/contexts/nr_contexts
# echo vaddr > kdamonds/0/contexts/0/operations
# echo 1 > kdamonds/0/contexts/0/targets/nr_targets
# echo $(pidof <workload>) > kdamonds/0/contexts/0/targets/0/pid_target
# 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
│ │ │ │ │ │ │ tried_regions/
│ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age
│ │ │ │ │ │ │ │ ...
│ │ │ │ │ │ ...
│ │ │ │ ...
│ │ ...
根
--
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>`. 将 ``update_schemes_tried_regions`` 写到
``state`` 文件,为kdamond的每个基于DAMON的操作方案,更新基于DAMON的操作方案动作的尝试区域目录。
将`clear_schemes_tried_regions`写入`state`文件,清除kdamond的每个基于DAMON的操作方案的动作
尝试区域目录。 关于基于DAMON的操作方案动作尝试区域目录的细节,请参考:ref:tried_regions 部分
<sysfs_schemes_tried_regions>`。
如果状态为 ``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`` )。你可以通过向文件写入
和从文件中读出,分别设置和获得初始监测目标区域的起始和结束地址。
每个区域不应该与其他区域重叠。 目录“N”的“结束”应等于或小于目录“N+1”的“开始”。
contexts/<N>/schemes/
---------------------
对于一版的基于DAMON的数据访问感知的内存管理优化,用户通常希望系统对特定访问模式的内存区
域应用内存管理操作。DAMON从用户那里接收这种形式化的操作方案,并将这些方案应用于目标内存
区域。用户可以通过读取和写入这个目录下的文件来获得和设置这些方案。
在开始时,这个目录只有一个文件,``nr_schemes``。向该文件写入一个数字(``N``),就可以
创建名为``0``到``N-1``的子目录的数量。每个目录代表每个基于DAMON的操作方案。
schemes/<N>/
------------
在每个方案目录中,存在五个目录(``access_pattern``、``quotas``、``watermarks``、
``stats`` 和 ``tried_regions``)和一个文件(``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`` 来更新统计信息的文件内容。
schemes/<N>/tried_regions/
--------------------------
当一个特殊的关键字 ``update_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
文件时,DAMON会在这个目录下创建从 ``0`` 开始命名的整数目录。每个目录包含的文件暴露了关于每个
内存区域的详细信息,在下一个 :ref:`聚集区间 <sysfs_monitoring_attrs>`,相应的方案的 ``动作``
已经尝试在这个目录下应用。这些信息包括地址范围、``nr_accesses`` 以及区域的 ``年龄`` 。
当另一个特殊的关键字 ``clear_schemes_tried_regions`` 被写入相关的 ``kdamonds/<N>/state``
文件时,这些目录将被删除。
tried_regions/<N>/
------------------
在每个区域目录中,你会发现四个文件(``start``, ``end``, ``nr_accesses``, and ``age``)。
读取这些文件将显示相应的基于DAMON的操作方案 ``动作`` 试图应用的区域的开始和结束地址、``nr_accesses``
和 ``年龄`` 。
用例
~~~~
下面的命令应用了一个方案:”如果一个大小为[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_pattern/sz/min
# echo 8192 > access_pattern/sz/max
# echo 0 > access_pattern/nr_accesses/min
# echo 5 > access_pattern/nr_accesses/max
# echo 10 > access_pattern/age/min
# echo 20 > access_pattern/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/damonitor/damo>`_ ,
而不是像上面那样手动读写文件。以上只是一个例子。
监测结果的监测点
================
DAMON通过一个tracepoint ``damon:damon_aggregated`` 提供监测结果. 当监测开启时,你可
以记录追踪点事件,并使用追踪点支持工具如perf显示结果。比如说::
# echo on > monitor_on_DEPRECATED
# perf record -e damon:damon_aggregated &
# sleep 5
# kill 9 $(pidof perf)
# echo off > monitor_on_DEPRECATED
# perf script
@@ -0,0 +1,49 @@
.. 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内存管理有它自己的术语,如果你还不熟悉它,请考虑阅读下面参考:
Documentation/admin-guide/mm/concepts.rst.
在此目录下,我们详细描述了如何与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
@@ -0,0 +1,198 @@
.. 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`` 的值。
监测KSM的收益
=============
KSM可以通过合并相同的页面来节省内存,但也会消耗额外的内存,因为它需要生成一些rmap_items
来保存每个扫描页面的简要rmap信息。其中有些页面可能会被合并,但有些页面在被检查几次
后可能无法被合并,这些都是无益的内存消耗。
1) 如何确定KSM在全系统范围内是节省内存还是消耗内存?这里有一个简单的近似计算方法供参考::
general_profit =~ pages_sharing * sizeof(page) - (all_rmap_items) *
sizeof(rmap_item);
其中all_rmap_items可以通过对 ``pages_sharing`` 、 ``pages_shared`` 、 ``pages_unshared``
和 ``pages_volatile`` 的求和而轻松获得。
2) 单一进程中KSM的收益也可以通过以下近似的计算得到::
process_profit =~ ksm_merging_pages * sizeof(page) -
ksm_rmap_items * sizeof(rmap_item).
其中ksm_merging_pages显示在 ``/proc/<pid>/`` 目录下,而ksm_rmap_items
显示在 ``/proc/<pid>/ksm_stat`` 。
从应用的角度来看, ``ksm_rmap_items`` 和 ``ksm_merging_pages`` 的高比例意
味着不好的madvise-applied策略,所以开发者或管理员必须重新考虑如何改变madvis策
略。举个例子供参考,一个页面的大小通常是4K,而rmap_item的大小在32位CPU架构上分
别是32B,在64位CPU架构上是64B。所以如果 ``ksm_rmap_items/ksm_merging_pages``
的比例在64位CPU上超过64,或者在32位CPU上超过128,那么应用程序的madvise策略应
该被放弃,因为ksm收益大约为零或负值。
监控KSM事件
===========
在/proc/vmstat中有一些计数器,可以用来监控KSM事件。KSM可能有助于节省内存,这是
一种权衡,因为它可能会在KSM COW或复制中的交换上遭受延迟。这些事件可以帮助用户评估
是否或如何使用KSM。例如,如果cow_ksm增加得太快,用户可以减少madvise(, , MADV_MERGEABLE)
的范围。
cow_ksm
在每次KSM页面触发写时拷贝(COW)时都会被递增,当用户试图写入KSM页面时,
我们必须做一个拷贝。
ksm_swpin_copy
在换入时,每次KSM页被复制时都会被递增。请注意,KSM页在换入时可能会被复
制,因为do_swap_page()不能做所有的锁,而需要重组一个跨anon_vma的KSM页。
--
Izik Eidus,
Hugh Dickins, 2009年11月17日。
@@ -0,0 +1,48 @@
.. SPDX-License-Identifier: GPL-2.0
.. include:: ../disclaimer-zh_CN.rst
:Original: Documentation/admin-guide/numastat.rst
:Translator: Tao Zou <wodemia@linux.alibaba.com>
=======================
Numa策略命中/未命中统计
=======================
/sys/devices/system/node/node*/numastat
所有数据的单位都是页面。巨页有独立的计数器。
numa_hit、numa_miss和numa_foreign计数器反映了进程是否能够在他们偏好的节点上分配内存。
如果进程成功在偏好的节点上分配内存则在偏好的节点上增加numa_hit计数,否则在偏好的节点上增
加numa_foreign计数同时在实际内存分配的节点上增加numa_miss计数。
通常,偏好的节点是进程运行所在的CPU的本地节点,但是一些限制可以改变这一行为,比如内存策略,
因此同样有两个基于CPU本地节点的计数器。local_node和numa_hit类似,当在CPU所在的节点上分
配内存时增加local_node计数,other_node和numa_miss类似,当在CPU所在节点之外的其他节点
上成功分配内存时增加other_node计数。需要注意,没有和numa_foreign对应的计数器。
更多细节内容:
=============== ============================================================
numa_hit 一个进程想要从本节点分配内存并且成功。
numa_miss 一个进程想要从其他节点分配内存但是最终在本节点完成内存分配。
numa_foreign 一个进程想要在本节点分配内存但是最终在其他节点完成内存分配。
local_node 一个进程运行在本节点的CPU上并且从本节点上获得了内存。
other_node 一个进程运行在其他节点的CPU上但是在本节点上获得了内存。
interleave_hit 内存交叉分配策略下想要从本节点分配内存并且成功。
=============== ============================================================
你可以使用numactl软件包(http://oss.sgi.com/projects/libnuma/)中的numastat工具
来辅助阅读。需要注意,numastat工具目前只在有少量CPU的机器上运行良好。
需要注意,在包含无内存节点(一个节点有CPUs但是没有内存)的系统中numa_hit、numa_miss和
numa_foreign统计数据会被严重曲解。在当前的内核实现中,如果一个进程偏好一个无内存节点(即
进程正在该节点的一个本地CPU上运行),实际上会从距离最近的有内存节点中挑选一个作为偏好节点。
结果会导致相应的内存分配不会增加无内存节点上的numa_foreign计数器,并且会扭曲最近节点上的
numa_hit、numa_miss和numa_foreign统计数据。
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,370 @@
.. 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许可的,因为经
过处理的版本(如经内核的构建系统)可能包含来自使用更严格许可证的文件的内容。
@@ -0,0 +1,280 @@
.. 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 架构上
你可以按下键盘组合键 `ALT-SysRq-<command key>`。
.. note::
一些键盘可能没有标识 'SySRq' 键。'SySRq' 键也被当做 'Print Screen'键。
同时有些键盘无法处理同时按下这么多键,因此你可以先按下键盘 `Alt` 键,
然后按下键盘 `SysRq` 键,再释放键盘 `SysRq` 键,之后按下键盘上命令键
`<command key>`,最后释放所有键。
在 SPARC 架构上
你可以按下键盘组合键 `ALT-STOP-<command key>` 。
在串行控制台(只针对 PC 类型的标准串口)
你可以发一个 ``BREAK`` ,然后在 5 秒内发送一个命令键,
发送 ``BREAK`` 两次将被翻译为一个正常的 BREAK 操作。
在 PowerPC 架构上
按下键盘组合键 `ALT - Print Screen` (或者 `F13`) - `<命令键>` 。
`Print Screen` (或者 `F13`) - `<命令键>` 或许也能实现。
在其他架构上
如果你知道其他架构的组合键,请告诉我,我可以把它们添加到这部分。
在所有架构上
写一个字符到 /proc/sysrq-trigger 文件,例如::
echo t > /proc/sysrq-trigger
这个命令键 `<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 键序列可以解决问题。(比如,像键盘组合键 `alt-sysrq-z` )
切换到另一个虚拟控制台(键盘操作 `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 命令的标题行将被传递给所有控制台
使用者,就好像当前日志级别是最大的一样。如果只发出标题头,则几乎可以肯定内核日志
级别太低。如果你需要控制台上的输出,那么你将需要临时提高控制台日志级别,通过使用
键盘组合键 `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> 添加键注册部分
@@ -0,0 +1,157 @@
.. 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插件,它可以有意生成非常不寻常的内核结构
布局(甚至是性能病态的布局),这在调试时非常有用。于构建时设置。
@@ -0,0 +1,170 @@
.. 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平面一被拒绝,因此上述编码仍然是官方的。