常规故障排除

来自 Arch Linux 中文维基
(重定向自General troubleshooting

本文介绍了一些常规的故障排除方法。有关特定应用程序的问题,请参阅该特定程序的 wiki 页面。

常用手段[编辑 | 编辑源代码]

这篇文章的某些内容需要扩充。

原因: 考虑到本页面的标题,应该要提及一些基本的“无脑的”解决方案,比如进行冷启动、更新到最新版本等…… (在 Talk:常规故障排除 中讨论)

出现的错误消息请务必阅读,这一点很重要。有时可能很难获得正确的错误消息(比如出错的是图形应用程序)。

  1. 在终端中运行应用程序,这样可以查看输出。
    1. 如果仍然没有足够的信息进行调试,请增加输出的详细度(通常加上参数 --verbose/-v/-V--debug/-d)。
    2. 如果没有这样的参数,可能是要在应用程序的配置文件中指定调试模式。
    3. 应用程序可能会有日志文件,日志文件通常位于 /var/log$HOME/.cache$HOME/.local
    4. 如果没有办法增加输出的详细度,那么运行 strace 和类似的命令总是可行的。
  2. 检查 日志。错误也可能在日志中留下痕迹,特别是当这个程序依赖于其他程序时。
    1. dmesg 从内核环形缓冲区读取日志。当磁盘由于某种原因无法访问时这很有用,但这也可能导致日志不完整,因为内核环形缓冲区的大小是有限的。如果可以的话尽量使用 journalctl
    2. journalctldmesg 有着更多的过滤选项,且默认使用人类可读的时间戳。
  3. 建议检查相关应用的问题跟踪列表,看看这是不是已知问题,以及是否存在解决方案。
    1. 应用通常是有问题跟踪列表的,具体取决于上游的选择,有时应用还有论坛,甚至有 IRC 频道。
    2. Arch Linux bugtracker 主要用于打包 bug。

额外支援[编辑 | 编辑源代码]

如果需要额外支援,你可以在 the forumsIRC 上提问。

当要求贴出 完整 的 输出 / 日志 时,不能仅仅贴出你认为的重要部分。信息来源应该包括:

  • 所有涉及到的命令的完整输出,不要只选择你认为相关的东西。
  • systemd 的 日志
    • 要获得更广泛的输出,请使用 systemd.log_level=debug 引导参数,但这会产生大量的输出,因此仅在确实需要时才启用它。
    • 不要使用 -x 参数,因为这会使输出混乱,让它难以阅读。
    • 除非需要上次启动的日志,否则请使用 -b 参数。不指定这个参数可能会导致日志很大,甚至超过在线剪贴板的允许大小。
  • 相关的配置文件
  • 相关的驱动程序
  • 相关软件包的版本
  • 内核日志:journalctl -kdmesg(都需要 root 权限)。
  • Xorg:所用的 显示管理器 的设置也决定了 Xorg 的日志位置。
    • Xorg.log 可能在以下位置之一:系统日志、/var/log/$HOME/.local/share/xorg/
    • 一些显示管理器,如 LightDM,可能会在它自己的日志目录里面也放一份 Xorg.log
  • Pacman:如果最近一次更新导致了问题,可以查看 /var/log/pacman.log
    • 使用 pacman--debug 参数也很有效。

最好将上述收集到的信息放到一个 在线剪贴板 里。

在线剪贴板将返回一个链接,你可以把它贴到论坛或 IRC。

此外,在提问前最好复习一下 如何正确报告问题

系统启动问题[编辑 | 编辑源代码]

这篇文章的某些内容需要扩充。

原因: 根据 Arch:Talk:Installation guide#Buggy graphics driver,或许应该加上在硬件上尝试 nomodeset 的内容? (在 Talk:常规故障排除 中讨论)

诊断系统启动问题时,了解问题出在启动的哪一阶段很重要。

  1. 固件(UEFI 或 BIOS)
    1. 往往只有非常基础的调试工具。
    2. 确保 安全启动 已关闭。
  2. 引导加载器
    1. 此处最容易引发故障的因素是修改了内核参数。
  3. initramfs
    1. 通常能提供一个 emergency shell。
    2. 在 shell 中可以用 dmesg 或 journal,取决于构建时选择的钩子。
  4. 实际系统
    1. 根据故障的严重程度,可能只需要调用 调试控制台 就行了。

如果某一阶段的调试工具无法修复损坏的组件,请尝试使用 包含最新 Arch Linux ISO 的U盘

控制台的输出信息[编辑 | 编辑源代码]

在启动过程完成以后,屏幕会被清空并显示登录提示符,这使得用户无法看到初始化过程中的输出和其中的错误信息。这一默认特性可以使用接下来几节中的方法进行修改。

请注意,无论选择下面哪个方法,在启动后通过 journalctl -kdmesg 都可以显示内核消息,用于检查错误。要显示本次启动的所有日志,请使用 journalctl -b

输出流控制[编辑 | 编辑源代码]

以下是适用于大多数终端模拟器的基本操作,包括虚拟终端 (VC):

  • Ctrl+s 暂停输出。
  • Ctrl+q 继续输出。

这样不仅会暂停输出,而且会暂停尝试打印到终端的程序,即暂停输出时会阻塞 write() 调用。 如果你的 init 进程出现冻结,请确保系统控制台没有暂停。

要查看已经显示过的错误信息,参见 Getty#将引导消息保留在 tty1 上

打印更多内核消息[编辑 | 编辑源代码]

在启动时大部分内核消息是隐藏的,添加不同的内核参数即可打印出更多消息,最简单的有这些参数:

  • debug,有如下效果:
    • 内核会提高它的控制台 日志级别,这样内核日志缓冲区中的所有消息都将打印到控制台。[1]
    • systemd 会提高它的日志级别,这会记录下调试信息,这些信息在其他地方是不会生成的。[2]
  • ignore_loglevel,对于内核来说它和 debugloglevel=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 种选择相对应,可取值为 modulefile
  • match_parameter 是要监控的模块或文件路径,后一种情况允许使用星号作为通配符。
  • flags 表示如何处理匹配结果,可以取 +p 来开始打印其消息,或者 -p 来撤消打印。

一些查询示例:

  • module i915 +p 打印来自 i915 内核模块的调试信息。
  • file drivers/gpu/drm/* +p 打印来自 DRM 驱动的调试信息。
  • file * +p 打印调试信息。

最后,要实际执行上述查询,可以这样:

  • 在运行时执行查询,运行命令:
# echo "查询" > /sys/kernel/debug/dynamic_debug/control
上述命令假设 debugfs 挂载到了 /sys/kernel/debug/,你可以用 mount 来确认。 [3]
  • 在系统启动时执行查询,添加 dyndbg="query" 内核参数

以上是对动态调试功能非常简略的概述,更多详细信息请参阅 文档

特定子系统的调试[编辑 | 编辑源代码]

在特定的子系统中,还有许多单独的参数可用于调试,例如 bootmem_debugsched_debug。此外 initcall_debug 用来检查启动卡死很有用(找到那些没有返回的调用)。特定的信息请查询 内核参数文档

netconsole[编辑 | 编辑源代码]

netconsole 是一个内核模块,它将所有内核日志消息(即 dmesg)通过网络发送到另一台计算机,不涉及到用户空间(如 syslogd)。 "netconsole" 这个名称不是很准确,因为它并不是真正的控制台,更像是远程日志记录服务。

它可以内置使用或作为模块使用。内置使用的 netconsole 在网卡之后就被初始化,并马上启动特定的接口。作为模块使用,主要用于捕获无显示器的计算机的内核崩溃输出,或者另一种情况就是用户空间有故障。

故障恢复控制台[编辑 | 编辑源代码]

在启动过程中的某个阶段获取一个交互式 shell 可以帮助你准确找出问题出在哪里,以及为何失败。有几个内核参数可以做到这一点,但它们都启动了一个正常的shell,可以随时 exit 让内核恢复正在执行的操作:

  • rescue 在根文件系统刚刚被挂载为读写模式的时候启动一个 shell
  • emergency 可以在更早的时候启动 shell,早于大部分文件系统挂载之前
  • init=/bin/sh(作为最后的选择)把 init 程序改成 root shell。因为 rescueemergency 都依赖于 systemd,而这可以在 systemd 坏掉的时候工作

还有一个选择,那就是 systemd 的 debug-shell,它在 tty9 上新增了一个 root shell,可以按 Ctrl+Alt+F9 来使用。这个功能可以通过在 内核参数 中添加 systemd.debug-shell,或者是 启用 debug-shell.service 来打开。

警告: 使用完后要记得禁用该服务,避免在每次启动时都打开 root shell 而带来安全风险。

调试内核模块[编辑 | 编辑源代码]

参阅 内核模块#获取信息

调试硬件问题[编辑 | 编辑源代码]

  • 按照 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+F1Ctrl+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[编辑 | 编辑源代码]

这篇文章的某些内容需要扩充。

原因: 需要更多关于其用法的信息 (在 Talk:常规故障排除 中讨论)

fuser 是一个用于识别进程占用的资源(如打开的文件、文件系统和 TCP/UDP 端口)的命令行工具。

fuser 由软件包 psmisc 提供,已经作为 base 元包的依赖安装。更多信息请查看 fuser(1)

会话权限[编辑 | 编辑源代码]

注意: 你必须使用 systemd 作为你的 init 进程,本地会话才能正常工作。[4] 它是各种设备的 polkit 权限和 ACL 所必需的 (参见 /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"[编辑 | 编辑源代码]

如果在运行程序时遇到类似于这样的错误:

error while loading shared libraries: libusb-0.1.so.4: cannot open shared object file: No such file or directory

使用 pacmanpkgfile 来查找包含丢失共享库的软件包:

$ 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 网站相关页面上把它报告给维护者。

参阅[编辑 | 编辑源代码]