常规故障排除
本文介绍了一些常规故障排除的方法。对于特定于应用程序的问题,请参考该程序的特定 Wiki 页面。
常规程序
务必阅读出现的任何错误消息,这一点至关重要。有时获取正确的错误消息可能比较困难,例如在图形应用程序中。
- 在终端中运行应用程序,以便检查输出。
- 如果调试信息仍然不足,请增加冗余度(通常使用
--verbose/-v/-V或--debug/-d)。 - 有时没有此类参数,需要在应用程序的配置文件中将其指定为指令。
- 应用程序也可能使用日志文件,通常位于
/var/log、$HOME/.cache或$HOME/.local。 - 如果没有增加冗余度的方法,始终可以运行 strace 及类似工具。
- 如果调试信息仍然不足,请增加冗余度(通常使用
- 检查 journal 日志。错误也可能在 journal 中留下痕迹,特别是如果它依赖于其他应用程序。
- dmesg 从内核环形缓冲区读取。这在磁盘因某种原因无法访问时很有用,但也可能导致日志不完整,因为内核环形缓冲区的大小不是无限的。如果可能,请使用 journalctl。
- journalctl 比 dmesg 具有更多 过滤选项,且默认使用人类可读的时间戳。
- 始终建议检查相关的上游问题追踪器,看看是否存在已知问题及已有的解决方案。
- 根据上游的选择,通常会有一个问题追踪器,有时还有论坛或 IRC 频道。
- 还有 Arch Linux bug 追踪器,它应主要用于报告打包相关的 Bug。
额外支持
寻求支持时,请发布 完整 的输出/日志,而不仅仅是您认为重要的部分。信息来源包括:
- 所涉及任何命令的完整输出——不要只选择您认为相关的部分。
- systemd 的 journal 日志。
- 如需更详尽的输出,请使用
systemd.log_level=debug引导参数。这会产生海量输出,因此仅在确实需要时启用。 - 不要使用
-x参数,因为它会不必要地使输出变得杂乱且难以阅读。 - 使用
-b参数,除非您需要之前引导的日志。不指定此参数可能会导致粘贴内容过大,甚至超出粘贴板(pastebin)的限制。
- 如需更详尽的输出,请使用
- 相关的配置文件
- 涉及的驱动程序
- 涉及的软件包版本
- 内核:
journalctl -k或dmesg(均需 root 权限)。 - Xorg:根据设置,所使用的 显示管理器 在此处也很重要。
Xorg.log可能位于以下几个位置之一:系统 journal、/var/log/或$HOME/.local/share/xorg/。- 某些显示管理器(如 LightDM)也可能将
Xorg.log放在其自身的日志目录中。
- Pacman:如果最近的升级导致了损坏,请查看
/var/log/pacman.log。- 使用 pacman 的
--debug参数可能会很有用。
- 使用 pacman 的
发布这些信息更好的方法之一是使用 粘贴板 (pastebin)。
随后会输出一个链接,您可以将其粘贴到论坛或 IRC 中。
此外,在提问前,您可能希望回顾一下 如何正确报告问题。
引导问题
诊断引导问题时,了解引导在哪个阶段失败非常重要。
- 固件 (UEFI 或 BIOS)
- 通常只有非常基础的调试工具。
- 确保已禁用 安全启动 (Secure Boot)。
- 引导加载程序
- 此处最常见的操作之一是修改内核参数。
- 引导加载程序阶段常见的引导问题可能是由 ACPI 引起的。
- initramfs
- 通常提供紧急 Shell (emergency shell)。
- 根据所选的 hook,其中可以使用 dmesg 或 journal。
- 实际系统
- 取决于损坏程度,此处仅需简单调用 调试 Shell 即可。
如果任何阶段提供的调试工具都不足以修复损坏的组件,请尝试使用例如 带有最新 Arch Linux ISO 的 USB 闪存盘。
控制台消息
引导过程结束后,屏幕会被清除并出现登录提示,导致用户无法读取 init 输出和错误消息。可以使用下文概述的方法修改此默认行为。
请注意,无论选择哪种选项,在引导后都可以通过 journalctl -k 或 dmesg 显示内核消息以供检查。要显示当前引导的所有日志,请使用 journalctl -b。
流控制
这是适用于大多数终端模拟器(包括虚拟控制台 VC)的基础管理操作。
- 按
Ctrl+s暂停输出。 - 按
Ctrl+q恢复输出。
这不仅会暂停输出,还会暂停尝试打印到终端的程序,因为只要输出处于暂停状态,它们就会阻塞在 write() 调用上。如果您的 init 似乎卡死了,请确保系统控制台没有被暂停。
要查看已经显示的错误消息,请参阅 Getty#让引导消息留在 tty1。
打印更多内核消息
大多数内核消息在引导期间是隐藏的。您可以通过添加不同的内核参数来查看更多消息。最简单的是:
debug,它具有以下效果:ignore_loglevel,它对内核的效果与debug或loglevel=8相同(因为调试消息位于7),但可以防止日志级别在引导后期被调低。
您还可以添加其他在某些情况下可能有用的参数:
earlyprintk=vga,keep在引导过程的极早期打印内核消息,以防内核在显示输出前崩溃。对于 EFI 系统,必须将vga改为efi。log_buf_len=16M分配更大的(16 MiB)内核消息缓冲区,以确保调试输出不会被覆盖。
生成调试内核消息
#打印更多内核消息 指出了如何将内核日志缓冲区打印到控制台,但该缓冲区本身不会包含它原本没有的消息(除了调试 systemd 输出)。本标题讨论从内核日志中获取更详细信息的方法。
动态调试
使用 pr_debug 或相关函数(如 dev_dbg()、drm_dbg() 和 bt_dev_dbg())打印的消息不会产生,除非您:
- 修改内核源代码,在需要的地方定义
DEBUG。 - 利用内核的 动态调试 (dynamic debug) 功能来启用调试消息。
本节将讨论如何使用动态调试,如果您已经查看了包含所有信息级别日志的内核日志,并希望从特定位置获得更多调试信息,这将非常有用。
首先,您运行的内核必须在编译时设置了 CONFIG_DYNAMIC_DEBUG 配置选项。对于 linux 内核,这已经是默认开启的,因此如果您使用的是该内核,则无需采取任何行动。
然后,您需要知道想从哪里看调试消息。有两个选择:
- 如果问题似乎仅限于某个模块,可以使用内核模块名称。例如,要排除 Intel 显卡 的故障,您可能关注
i915DRM 内核模块。 - 使用内核中与您感兴趣的功能相对应的目录。您需要查看(或在线浏览)内核 源代码以了解其结构。例如,要检查所有 DRM 内核模块的调试消息,可以使用路径 drivers/gpu/drm。
有了这些消息“来源”,您必须想出一个动态调试查询,以指示启用哪些调试消息,格式如下:
match_type match_parameter flags
其中:
- match_type 是匹配类型。对应前面的两个选项,可以是
module或file。 - match_parameter 是要监视的模块或文件路径。在后一种情况下,允许使用星号作为通配符。
- flags 决定对匹配项执行的操作。可以是
+p开始打印其消息,或-p撤销该操作。
查询示例:
module i915 +p打印来自i915内核模块的调试消息。file drivers/gpu/drm/* +p打印来自 DRM 驱动程序的调试消息。file * +p打印所有调试消息。
最后,要实际执行查询,您可以:
- 在运行时执行,通过运行:
# echo "query" > /sys/kernel/debug/dynamic_debug/control
- 在引导时执行,通过添加
dyndbg="query"内核参数。
这只是动态调试功能的极大简化概述;详见 官方文档。
特定子系统调试
还有许多独立的调试参数用于启用特定子系统的调试,例如 bootmem_debug、sched_debug。此外,initcall_debug 对于调查引导死机很有用。(寻找未返回的调用。)请查阅 内核参数文档 获取具体信息。
netconsole
netconsole 是一个内核模块,它通过网络将所有内核日志消息(即 dmesg)发送到另一台计算机,而无需涉及用户空间(如 syslogd)。“netconsole”这个名字有点名不副实,因为它并不是真正的“控制台”,更像是一种远程日志服务。
它可以以内建方式或模块方式使用。内建的 netconsole 会在网卡之后立即初始化,并尽快启动指定的接口。该模块主要用于从无头(headless)机器捕获内核恐慌(kernel panic)输出,或在用户空间不再起作用的其他情况下使用。
恢复 Shell
在引导过程的某个阶段获取交互式 Shell 可以帮助您精确定位故障发生的位置和原因。有几个内核参数可以实现这一点,但它们都会启动一个普通的 Shell,您可以 exit 退出它让内核恢复之前的操作:
rescue在根文件系统以读/写方式重新挂载后不久启动 Shell。emergency更早地启动 Shell,在大多数文件系统挂载之前。init=/bin/sh(作为最后手段)将 init 程序更改为 root shell。rescue和emergency都依赖 systemd,但即使 systemd 损坏,此方法也应该有效。
另一个选择是 systemd 的 debug-shell,它在 tty9 上添加了一个 root shell(通过 Ctrl+Alt+F9 访问)。可以通过在 内核参数 中添加 systemd.debug_shell,或通过 启用 debug-shell.service 来开启它。
调试内核模块
参见 内核模块#获取信息。
调试硬件
- 您可以按照 udev#调试输出 中的说明显示有关硬件的额外调试信息。
- 确保系统中已应用 微码 (Microcode) 更新。
- 要测试 RAM,请参见 压力测试#Memtest86+。
- 要查看系统是否过热,请使用 lm_sensors。
- 要检查存储健康状况,请参见 S.M.A.R.T.。
调试死机
不幸的是,死机通常很难调试,且其中一些需要很长时间才能重现。有些类型的死机比其他类型的更容易调试:
- 声音还在播放吗?如果是,可能只是显示卡死。这可能是视频驱动程序的问题。
- 机器还有响应吗?如果切换到另一个 TTY 不起作用,请尝试 SSH。
- 磁盘活动 LED(如果有)是否指示正在进行大量磁盘写入?沉重的交换(swapping)可能会暂时冻结系统。有关大文件写入导致死机的信息,请参阅 此 StackExchange 回答。
如果别无他法,请尝试 正常 关机。按 一次 电源按钮可能会解除系统死机并显示经典的“关机屏幕”,显示正在停止的所有单元。或者,使用神奇的 SysRq 键也可能有助于实现正常关机。这非常重要,因为 journal 可能包含机器卡死原因的线索。非正常关机可能无法将 journal 写入磁盘。整个机器无响应的硬死机更难调试,因为日志无法及时写入磁盘。
如果死机导致无法向磁盘写入任何内容,远程日志记录可能会有所帮助。可以使用一种粗糙的远程日志方案(需要从另一台设备调用)进行基础调试:
$ ssh freezing_host journalctl -f
许多导致整个系统不再响应且需要强制关机的致命死机可能与有缺陷的固件、驱动程序或硬件有关。尝试不同的内核(参见 内核#调试回归)甚至不同的 Linux 发行版或操作系统,更新固件并运行硬件诊断,可能有助于找到问题。
如果死机导致无法收集任何日志或调试所需的其他信息,请尝试在 Live 环境中重现死机。如果重现死机需要图形环境,或者在 archiso 上就能重现,请使用其他发行版的 Live 环境(最好不是基于 Arch Linux 的),以排除死机与内核版本或补丁有关的可能性。如果死机在 Live 环境中仍然发生,很有可能是硬件相关的。如果不发生了,则需要注意两个系统之间的差异。不同的配置、版本差异、内核参数及其他类似变更可能已经修复了死机。
此外,闪烁的大写锁定(caps lock)键 LED 可能指示 内核恐慌 (kernel panic)。某些设置在发生内核恐慌时可能不会显示 TTY,这可能会令人困惑并被误认为另一种死机。
调试回归问题
如果更新导致了问题,但 降级 特定软件包后修复了该问题,那么它很可能是一个 回归 (regression)。如果这是在正常的完整系统升级后发生的,请检查您的 pacman.log 以确定可能是哪个或哪些软件包导致了问题。调试回归最重要的部分是检查问题是否已被修复,这可以节省大量时间。为此,首先确保应用程序已完全更新(例如,确保版本与 官方仓库 中的一致)。如果已经是最新版本或更新后问题依旧,请尝试使用开发版本(通常是 VCS 版本),它们可能已在 AUR 中打包。如果这修复了问题,而包含修复的版本尚未进入官方仓库,请等待新版本进入后再切换回官方版本。
如果问题仍然存在,请调试该问题并/或对应用程序进行 二分搜索 (bisect),并在上游 bug 追踪器上报告 bug 以便修复。
内核升级后无法使用某些外设
这通常(但可能不仅)表现为:
- 新插入的 USB 设备在 dmesg 中显示,但不在
/dev/中显示; - 在内核更新前未使用的文件系统无法挂载;
- 笔记本电脑上在内核更新前未使用的有线/无线连接无法使用;
- 当使用 modprobe 加载内核包更新前未使用的模块时,提示
FATAL: Module module not found in directory /lib/module/kernelversion。
正如 系统维护#升级后重启 中部分提到的,当您更新软件包时内核并未更新,只有在随后的重启时才会更新。与此同时,位于 /usr/lib/modules/kernelversion/ 的内核模块在安装新内核时会被 pacman 移除。正如 FS#16702 中所解释的,这种方法避免了在系统中留下不由包管理器处理的文件,但会导致上述症状。要修复这些问题,请在更新内核后例行重启。长期演进(尚待实施)将是使用带版本的内核软件包:主要阻碍在于如何处理不再需要的旧内核版本的移除。
另一个解决方案是 kernel-modules-hook,其中两个 pacman hook 使用 rsync 在内核更新后将内核模块保留在文件系统中,并在 启用 后的四周后由 linux-modules-cleanup.service 标记旧模块以供移除。
软件包管理
有关常规主题请参阅 Pacman#故障排除,有关 PGP 密钥问题请参阅 pacman/软件包签名#故障排除。
修复损坏的系统
如果执行了 局部升级,请尝试更新整个系统。可能需要重启。
# pacman -Syu
如果您通常引导进入图形界面且引导失败,或许可以按下 Ctrl+Alt+F1 到 Ctrl+Alt+F6 进入一个可用的 tty,以便从中运行 pacman。
如果系统损坏严重到无法运行 pacman,请 使用 USB 闪存盘、光盘或通过 PXE 网络引导每月发布的 Arch ISO。(不要遵循安装指南的其余部分。)
挂载您的根文件系统
# mount /dev/rootFileSystemDevice /mnt
挂载您单独创建的其他任何分区,并为它们全部添加 /mnt 前缀,即:
# mount /dev/bootDevice /mnt/boot
尝试在 chroot 后使用系统的 pacman
# arch-chroot /mnt # pacman -Syu
如果失败,退出 chroot 并尝试:
# pacman -Syu --sysroot /mnt
如果还是失败,尝试:
# pacman -Syu --root /mnt --cachedir /mnt/var/cache/pacman/pkg
fuser
fuser 是一个命令行实用程序,用于识别正在使用文件、文件系统和 TCP/UDP 端口等资源的进程。
fuser 由 psmisc 软件包提供,该包应已作为 base 元软件包 的依赖项安装。详见 fuser(1)。
会话权限
/usr/lib/udev/rules.d/70-uaccess.rules 和 [5])首先,确保您在 X 中有一个有效的本地会话:
$ loginctl show-session $XDG_SESSION_ID
输出中应包含 Remote=no 和 Active=yes。如果没有,请确保 X 在发生登录的同一个 tty 上运行。这是保留 logind 会话所必需的。
基本的 polkit 操作不需要进一步设置。某些 polkit 操作即使在本地会话中也需要进一步身份验证。为此,必须运行一个 polkit 身份验证代理。更多信息请参阅 polkit#身份验证代理。
消息:"error while loading shared libraries"
如果在使用程序时遇到类似以下的错误:
error while loading shared libraries: libusb-0.1.so.4: cannot open shared object file: No such file or directory
使用 pacman 或 pkgfile 搜索拥有该缺失库的软件包:
$ pacman -F libusb-0.1.so.4
extra/libusb-compat 0.1.5-1
usr/lib/libusb-0.1.so.4
在这种情况下,需要 安装 libusb-compat 软件包。或者,在 soname 提升 后,请求该库的程序可能需要重新构建。
该错误也可能意味着您用于安装程序的软件包未在其 PKGBUILD 中将该库列为依赖项:如果是官方软件包,请 报告 Bug;如果是 AUR 软件包,请通过其在 AUR 网站上的页面向维护者报告。
参见
- 新手故障排除指南
- UBCD 工具列表 - 类似于 Memtest 的工具,可添加到 UltimateBootCD.com 的 grub.cfg 中
- Wikipedia: BIOS 引导分区
- 键盘快捷键#内核 (SysRq)
- 关于向串口控制台记录调试日志的 systemd 文档
- Archive.org 上的 如何隔离 Linux ACPI 问题