常規故障排除
本文介紹了一些常規的故障排除方法。有關特定應用程式的問題,請參閱該特定程序的 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