常规故障排除
本文介绍了一些常规的故障排除方法。有关特定应用程序的问题,请参阅该特定程序的 wiki 页面。
常用手段[编辑 | 编辑源代码]
出现的错误消息请务必阅读,这一点很重要。有时可能很难获得正确的错误消息(比如出错的是图形应用程序)。
- 在终端中运行应用程序,这样可以查看输出。
- 如果仍然没有足够的信息进行调试,请增加输出的详细度(通常加上参数
--verbose
/-v
/-V
或--debug
/-d
)。 - 如果没有这样的参数,可能是要在应用程序的配置文件中指定调试模式。
- 应用程序可能会有日志文件,日志文件通常位于
/var/log
、$HOME/.cache
或$HOME/.local
。 - 如果没有办法增加输出的详细度,那么运行 strace 和类似的命令总是可行的。
- 如果仍然没有足够的信息进行调试,请增加输出的详细度(通常加上参数
- 检查日志。错误也可能在日志中留下痕迹,特别是当这个程序依赖于其他程序时。
- dmesg 从内核环形缓冲区读取日志。当磁盘由于某种原因无法访问时这很有用,但这也可能导致日志不完整,因为内核环形缓冲区的大小是有限的。如果可以的话尽量使用 journalctl。
- journalctl 比 dmesg 有着更多的过滤选项,且默认使用人类可读的时间戳。
- 建议检查相关应用的问题跟踪列表,看看这是不是已知问题,以及是否存在解决方案。
- 应用通常是有问题跟踪列表的,具体取决于上游的选择,有时应用还有论坛,甚至有 IRC 频道。
- Arch Linux bugtracker 主要用于打包 bug。
额外支援[编辑 | 编辑源代码]
如果需要额外支援,你可以在 the forums 或 IRC 上提问。
当要求贴出完整的 输出 / 日志 时,不能仅仅贴出你认为的重要部分。信息来源应该包括:
- 所有涉及到的命令的完整输出,不要只选择你认为相关的东西。
- systemd 的日志。
- 要获得更广泛的输出,请使用
systemd.log_level=debug
引导参数,但这会产生大量的输出,因此仅在确实需要时才启用它。 - 不要使用
-x
参数,因为这会使输出混乱,让它难以阅读。 - 除非需要上次启动的日志,否则请使用
-b
参数。不指定这个参数可能会导致日志很大,甚至超过在线剪贴板的允许大小。
- 要获得更广泛的输出,请使用
- 相关的配置文件
- 相关的驱动程序
- 相关软件包的版本
- 内核日志:
journalctl -k
或dmesg
(都需要 root 权限)。 - Xorg:所用的显示管理器的设置也决定了 Xorg 的日志位置。
Xorg.log
可能在以下位置之一:系统日志、/var/log/
或$HOME/.local/share/xorg/
。- 一些显示管理器,如 LightDM,可能会在它自己的日志目录里面也放一份
Xorg.log
。
- Pacman:如果最近一次更新导致了问题,可以查看
/var/log/pacman.log
。- 使用 pacman的
--debug
参数也很有效。
- 使用 pacman的
最好将上述收集到的信息放到一个在线剪贴板里。
在线剪贴板将返回一个链接,你可以把它贴到论坛或 IRC。
此外,在提问前最好复习一下如何正确报告问题。
系统启动问题[编辑 | 编辑源代码]
诊断系统启动问题时,了解问题出在启动的哪一阶段很重要。
- 固件(UEFI 或 BIOS)
- 往往只有非常基础的调试工具。
- 确保安全启动已关闭。
- 引导加载器
- 此处最容易引发故障的因素是修改了内核参数。
- initramfs
- 通常能提供一个 emergency shell。
- 在 shell 中可以用 dmesg 或 journal,取决于构建时选择的钩子。
- 实际系统
- 根据故障的严重程度,可能只需要调用调试控制台就行了。
如果某一阶段的调试工具无法修复损坏的组件,请尝试使用包含最新 Arch Linux ISO 的U盘。
控制台的输出信息[编辑 | 编辑源代码]
在启动过程完成以后,屏幕会被清空并显示登录提示符,这使得用户无法看到初始化过程中的输出和其中的错误信息。这一默认特性可以使用接下来几节中的方法进行修改。
请注意,无论选择下面哪个方法,在启动后通过 journalctl -k
或 dmesg
都可以显示内核消息,用于检查错误。要显示本次启动的所有日志,请使用 journalctl -b
。
输出流控制[编辑 | 编辑源代码]
以下是适用于大多数终端模拟器的基本操作,包括虚拟终端 (VC):
- 按
Ctrl+s
暂停输出。 - 按
Ctrl+q
继续输出。
这样不仅会暂停输出,而且会暂停尝试打印到终端的程序,即暂停输出时会阻塞 write()
调用。 如果你的 init 进程出现冻结,请确保系统控制台没有暂停。
要查看已经显示过的错误信息,参见 Getty#将引导消息保留在 tty1 上。
打印更多内核消息[编辑 | 编辑源代码]
在启动时大部分内核消息是隐藏的,添加不同的内核参数即可打印出更多消息,最简单的有这些参数:
debug
,有如下效果:ignore_loglevel
,对于内核来说它和debug
或loglevel=8
(debug 对应的级别是7
)有相同的效果,但在启动后期日志级别不会提高。
在特定情况下可以添加的参数还有这些:
earlyprintk=vga,keep
打印启动过程中最早期的内核消息,用在还没显示输出就崩溃的情况下。在 UEFI 系统上需要把vga
改成efi
。log_buf_len=16M
将分配一个更大的 (16 MiB) 内核日志缓冲区,确保调试输出不会被覆盖。
生成更多内核调试信息[编辑 | 编辑源代码]
#打印更多内核消息描述了如何将内核日志缓冲区中的内容打印到控制台,但内核日志缓冲区也不是所有消息都有(除了 systemd 的 debug 输出)。本节讨论如何获取比内核日志更详细的信息。
动态调试[编辑 | 编辑源代码]
由函数 pr_debug 或类似函数 dev_dbg()
, drm_dbg()
和 bt_dev_dbg()
生成的消息不在内核日志里,除非:
- 修改内核源代码,在需要的地方定义
DEBUG
。 - 利用内核的动态调试功能来启用调试消息。
本节讨论动态调试的用法,当你已经查看了所有内核日志,甚至是 information 级别的日志,但还是想从特定位置获取更多调试信息,那么动态调试很有用。
首先,你用的内核必须是用 CONFIG_DYNAMIC_DEBUG
内核配置选项编译出来的,linux包 包的内核已经满足了要求,如果用这个内核就无需执行任何操作。
然后需要确定所需调试信息在哪,有几种选择:
- 如果问题与特定模块有关,就找到内核模块的名称。比如要排除 Intel 图形处理器的故障,就需要关注
i915
DRM 内核模块. - 找到内核中相关功能对应的目录,这需要查看(或在线导航)内核源代码以了解其结构。例如,要查看所有 DRM 内核模块的调试消息,可以使用路径 drivers/gpu/drm。
要使用该消息“源”,就必须发起一次动态调试查询,指明要启用哪些调试消息,格式如下:
match_type match_parameter flags
其中:
- match_type 是匹配类型,与上述 2 种选择相对应,可取值为
module
或file
。 - match_parameter 是要监控的模块或文件路径,后一种情况允许使用星号作为通配符。
- flags 表示如何处理匹配结果,可以取
+p
来开始打印其消息,或者-p
来撤消打印。
一些查询示例:
module i915 +p
打印来自i915
内核模块的调试信息。file drivers/gpu/drm/* +p
打印来自 DRM 驱动的调试信息。file * +p
打印调试信息。
最后,要实际执行上述查询,可以这样:
- 在运行时执行查询,运行命令:
# echo "查询" > /sys/kernel/debug/dynamic_debug/control
- 在系统启动时执行查询,添加
dyndbg="query"
内核参数。
以上是对动态调试功能非常简略的概述,更多详细信息请参阅文档。
特定子系统的调试[编辑 | 编辑源代码]
在特定的子系统中,还有许多单独的参数可用于调试,例如 bootmem_debug
、sched_debug
。此外 initcall_debug
用来检查启动卡死很有用(找到那些没有返回的调用)。特定的信息请查询内核参数文档。
netconsole[编辑 | 编辑源代码]
netconsole 是一个内核模块,它将所有内核日志消息(即 dmesg)通过网络发送到另一台计算机,不涉及到用户空间(如 syslogd)。 "netconsole" 这个名称不是很准确,因为它并不是真正的控制台,更像是远程日志记录服务。
它可以内置使用或作为模块使用。内置使用的 netconsole 在网卡之后就被初始化,并马上启动特定的接口。作为模块使用,主要用于捕获无显示器的计算机的内核崩溃输出,或者另一种情况就是用户空间有故障。
故障恢复控制台[编辑 | 编辑源代码]
在启动过程中的某个阶段获取一个交互式 shell 可以帮助你准确找出问题出在哪里,以及为何失败。有几个内核参数可以做到这一点,但它们都启动了一个正常的shell,可以随时 exit
让内核恢复正在执行的操作:
rescue
在根文件系统刚刚被挂载为读写模式的时候启动一个 shellemergency
可以在更早的时候启动 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#Debug output 的说明可以显示额外硬件调试信息。
- 确保你的系统已经安装了微码更新。
- 要测试内存请参阅 MemTest86+。
- 要排查系统是否超温请使用 lm_sensors。
- 要检查存储器的健康状况,请参阅 S.M.A.R.T.。
调试系统卡死问题[编辑 | 编辑源代码]
不幸的是,系统卡死通常很难调试,并且有些需要很长时间才能复现。有些类型的卡死调试起来相对容易一点:
- 声音还在播放?这种情况可能只是显示卡死了,显卡驱动可能有问题。
- 系统还有响应吗?如果切换到其他 TTY 不行的话就试试 SSH。
- 硬盘活动指示灯(如果有的话)是否在指示有大量数据在读写?大量的内存交换也会暂时卡死系统。关于大量写入硬盘时卡死的情况请参阅这个 StackExchange 回答。
如果上述都不行,尝试一次完整的关机。按一次电源键或许可以使系统有反应,并显示“关机画面”,关机画面包含了所有正在停止的单元。或者使用神奇的 SysRq 键也可以进行完整关机。完整关机很重要,因为日志可能提示了系统卡死的原因。在非正常关闭时日志可能不会写入磁盘。系统毫无反应的情况更难调试,因为日志无法及时写入磁盘。
如果卡死以后没法将任何内容写入磁盘,可以尝试远程日志。以下是一个粗略的远程日志方案,需要从另一个设备发起,可用于基本调试:
$ ssh freezing_host journalctl -f
许多致命卡死(整个系统无响应只能强制关机)可能与固件、驱动程序或硬件存在缺陷有关。尝试不同的内核(请参阅内核#调试回退),甚至换个 Linux 发行版或操作系统,还有更新固件并运行硬件诊断可能有助于发现问题。
如果卡死以后无法收集用来调试的日志或信息,请尝试在 live 环境中重现卡死。如果需要图形环境来重现,或者如果在 archiso 上成功重现了卡死,请更换不同发行版的 live 环境,最好不是基于 Arch Linux 的发行版,以排除卡死与版本或内核补丁相关的可能性。如果在 live 环境中仍然卡死,则很可能与硬件有关。如果不再发生卡死,那就需要了解两个系统的差异。配置、版本和内核参数的不同,以及其他类似的更改可能已经解决了卡死问题。
但是,大写锁定指示灯闪烁可能表示内核崩溃。当发生内核崩溃时,因为某些设置,TTY 可能不会显示,导致内核崩溃被误以为是另一种卡死。
处理软件倒退问题[编辑 | 编辑源代码]
如果是更新导致的问题,且降级特定包可以解决问题,则可能是软件倒退。 如果在正常的完整系统升级后发生这种情况,请检查 pacman.log
来确定哪个软件包可能导致了该问题。处理软件倒退最重要的是检查新版本是否已解决问题,这样可以节省大量时间。为此,首先确保应用程序已完全更新(确保程序与官方仓库中的版本相同)。如果已经最新或者更新不能解决问题,请尝试使用实际的最新版本,通常是 -git 版本,它可能已经打包在 AUR 中。如果这样能解决问题,并且已修复的版本还不在官方仓库中,请等待新版本打包,然后切换回官方仓库的版本。
如果问题仍然存在,请调试程序或二分查找程序的代码提交历史,并在上游的问题跟踪系统里报告错误,以便修复问题。
内核升级后部分外设无法使用[编辑 | 编辑源代码]
通常(但可能不仅仅)表现为:
- 新插入的 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 钩子,在内核更新后使用 rsync 将内核模块保留在文件系统上,并启用 linux-modules-cleanup.service
在四周后删除旧模块。
软件包管理[编辑 | 编辑源代码]
参阅适用于一般主题的 Pacman#疑难解答,以及适用于 PGP 密钥问题的 pacman/软件包签名#问题解决。
修复受损的系统[编辑 | 编辑源代码]
如果进行了部分升级,请尝试升级整个系统,可能还需要重启一次。
# pacman -Syu
如果以往是启动到图形界面,但这次失败了,可以尝试按 Ctrl+Alt+F1
到 Ctrl+Alt+F6
来获得一个能运行 pacman 的控制台。
如果系统损坏严重无法运行 pacman,使用U盘、光盘或带 PXE 的网络上的 Arch ISO 来启动电脑。(不要执行安装指南里的其余操作)
挂载根文件系统:
[ISO] # mount /dev/rootFileSystemDevice /mnt
挂载其余的独立分区,在它们前面加上前缀 /mnt
,例如:
[ISO] # mount /dev/bootDevice /mnt/boot
尝试使用原系统的 pacman:
[ISO] # arch-chroot /mnt [chroot] # pacman -Syu
如果失败了,退出 chroot 并尝试:
[ISO] # pacman -Syu --sysroot /mnt
如果也失败了,尝试:
[ISO] # 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
and Active=yes
字样。如果没有,确保 X 运行在和登录时一样的 tty 里面。这是保留登录会话所必须的。
基本 polkit 操作不需要额外的配置。但有一些 polkit 操作需要请求额外的身份认证,即使是本地会话也是如此。为了达成这项工作,必须运行一个 polkit 身份认证组件。更多信息可参见 polkit#身份认证组件。
[编辑 | 编辑源代码]
如果在运行程序时遇到类似于这样的错误:
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 网站相关页面上把它报告给维护者。
参阅[编辑 | 编辑源代码]
- A how-to in troubleshooting for newcomers
- List of Tools for UBCD - Memtest-like tools to add to grub.cfg on UltimateBootCD.com
- Wikipedia:BIOS Boot partition
- Arch:REISUB
- Debug Logging to a Serial Console on Freedesktop.org
- How to Isolate Linux ACPI Issues on Archive.org