本文介紹了一些常規的故障排除方法。有關特定應用程式的問題,請參閱該特定程序的 wiki 頁面。
常用手段
注意細節
為了解決遇到的問題,對當前使用的這個程序,你應該有一個基本的了解,這是 至關重要 的。它是如何工作的,它依賴什麼才能正常運行?如果不能很好地回答這些問題,最好閱讀一下這些出錯程序的 Archwiki 文章。一旦你覺得你已經理解了它,你將更容易找出問題的原因。
常見問題 / 檢查項
下面列出了許多常見問題,用於排查故障。在每個問題下都有注釋,說明你該如何回答這個問題,緊接著的是一些如何收集數據的簡單示例,還有查看各種日誌的工具。
- 出現了什麼故障?
- 請儘可能精確地描述問題,這將幫助你在查找特定信息的時候不至感到困惑或扯到別的方面去。
- 是否顯示了錯誤信息?(如果有的話)
- 將包含相關 錯誤信息 的 完整輸出 複製並粘貼到類似
$HOME/issue.log
這樣單獨的文件中。例如,可以將以下 mkinitcpio 命令的輸出轉發到$HOME/issue.log
: $ mkinitcpio -p linux >> $HOME/issue.log
- 將包含相關 錯誤信息 的 完整輸出 複製並粘貼到類似
- 可以復現這個故障碼?
- 如果是這樣,請 按步驟 給出 確切的 指示/命令來做到這一點。
- 第一次遇到這些故障的時間,以及從沒有故障到故障發生之間你修改了什麼內容?
尋求解決
不要通過這樣的表述來尋求問題的解決:
程序 X 不工作了。
描述整個系統的環境更有助於解決問題,比如:
應用程式 X 在執行 Z 任務時,會報出 Y 錯誤,條件是 A 和 B。
額外支援
利用你眼前的所有信息,你應該對系統裡發生了什麼有一個較好的認識,並且可以開始著手修復了。
如果需要額外支援,官方論壇 或 IRC (irc.freenode.net 上的 #archlinux 頻道) 都可以提供幫助。更多頻道可參考 IRC channels。
當要求貼出 完整 的 輸出 / 日誌 時,不能僅僅貼出你認為的重要部分。信息來源應該包括:
- 所有涉及到的命令的完整輸出,不要只選擇你認為相關的東西。
- 來自 systemd 的
journalctl
的輸出。要獲取更多的輸出,請使用systemd.log_level=debug
引導參數。 - 日誌文件(看一下
/var/log
目錄) - 相關的配置文件
- 相關的驅動程序
- 相關軟體包的版本
- 內核相關:
dmesg
。對於啟動問題,至少貼出最後 10 行,多貼一些當然更好。 - 網絡相關:相關命令的完整輸出,再加上所有相關配置文件。
- Xorg 相關:
/var/log/Xorg.0.log
,如果你已經覆蓋了出問題的日誌,就貼在這之前的日誌。 - Pacman 相關:如果最近的更新弄壞了什麼東西,請到
/var/log/pacman.log
找它。
貼出這些信息有一個更好的方式,就是使用在線剪貼板 (pastebin)。你可以 安裝 pbpstAUR 或 gist包 來自動上傳信息。例如,要上傳這次啟動以來的 systemd 日誌,可以這麼做:
# journalctl -xb | pbpst -S
這將返回一個連結,你可以把它貼到論壇或 IRC。
系統啟動問題
診斷 啟動過程 中的問題主要是修改 內核參數,然後重啟系統。
如果系統無法啟動,可以從 live 鏡像 啟動並 chroot 到現有系統。
控制台的輸出信息
在啟動過程完成以後,屏幕會被清空並顯示登錄提示符,這使得用戶無法看到初始化過程中的輸出和其中的錯誤信息。這一默認特性可以使用接下來幾節中的方法進行修改。
請注意,無論選擇下面哪個方法,在啟動後通過使用 dmesg
或 journalctl -b
都可以顯示內核消息,用於檢查錯誤。
輸出流控制
以下是適用於大多數終端模擬器的基本操作,包括虛擬終端 (vc):
- 按
Ctrl+S
暫停輸出 - 按
Ctrl+Q
繼續輸出
這樣不僅會暫停輸出,而且會暫停嘗試列印到終端的程序,即暫停輸出時會阻塞 write()
調用。 如果你的 init 進程出現凍結,請確保系統控制台沒有暫停。
要查看已經顯示過的錯誤信息,參見 Getty#將引導消息保留在 tty1 上。
回滾顯示
回滾顯示允許用戶查看已經從控制台滾動過去並消失的文字內容。這通常是在視頻適配器和顯示設備之間創建緩衝(稱為回滾緩衝區)實現的。默認情況下,將緩衝的內容上下滾動的快捷鍵是 Shift+PageUp
和 Shift+PageDown
。
如果回滾內容沒有完全包含足夠的信息,可能需要擴大回滾緩衝區的大小來容納更多輸出。這可以通過配置內核的 framebuffer console(fbcon,幀緩衝控制台)來實現,修改 內核參數 fbcon=scrollback:Nk
即可,其中 N
是緩衝區大小,單位是 kB,默認是 32k。
如果這不奏效,你的 framebuffer console 可能沒有正確地啟用。參閱 Framebuffer Console documentation 來查找其他影響參數,比如修改幀緩衝驅動。
Debug 輸出
在啟動時,大部分來自內核的消息都是隱藏的,可以加入不同的內核參數來輸出更多信息。最簡單的是這些:
-
debug
可以同時啟用來自內核和 systemd 的調試信息 -
ignore_loglevel
強制顯示 所有 內核消息
在特定情況下有用的其他參數如下:
-
earlyprintk=vga,keep
在早期啟動過程中就輸出內核消息,用於內核在有輸出前就崩潰的情況下。在 EFI 系統上要把vga
改成efi
。 -
log_buf_len=16M
用於分配一個更大 (16MB) 的內核消息緩衝區,用來保證 debug 輸出不被覆蓋。
還有很多獨立的調試參數,用於在特定的子系統中啟用調試,例如 bootmem_debug
和 sched_debug
。更多詳細信息請參考 kernel parameter documentation。
故障恢復控制台
在啟動過程中的某個階段獲取一個交互式 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
來打開。注意在使用完後禁用該服務,避免在每次啟動時都打開 root shell 而帶來安全風險。
Intel 顯卡造成的黑屏
這很可能是 kernel mode setting 的問題造成的。嘗試 disabling modesetting 或者修改 video port。
加載內核時卡住
嘗試添加 acpi=off
內核參數來關閉 ACPI。
調試內核模塊
參見 Kernel modules#Obtaining information。
調試硬體
- 按照 udev#Debug output 的說明可以顯示額外硬體調試信息。
- 確保你的系統已經安裝了 Microcode 更新。
- 使用 Memtest86+ 來測試設備的 RAM,不可靠的 RAM 可能會導致一些非常奇怪的問題,從隨機崩潰到數據損壞都有可能。
內核崩潰(Kernel panic)
Linux 內核進入不可恢復的故障狀態時,即發生了「內核崩潰」 (kernel panic)。這種狀態通常來源於錯誤的硬體驅動程序,導致內核死鎖,無響應並需要重新啟動。在死鎖之前,會生成一條診斷消息,其中包括:發生崩潰時的機器狀態,導致崩潰的內核函數的調用棧,以及當前加載的模塊的列表。幸運的是,使用 mainline(主線)版本的內核(比如官方倉庫提供的內核)不會經常發生內核崩潰,但是當它們發生時,你需要知道如何處理它們。
oops=panic
或者在 /proc/sys/kernel/panic_on_oops
中寫入 1
來強制用 panic 代替可恢復的 oops。如果你認為自動恢復 oops 導致了小概率的系統不穩定,進而導致了後來的錯誤難以被診斷,那麼建議你這樣做。查看 panic 信息
如果在早期啟動過程中發生了 kernel panic,你或許會在控制台上看到包含 "Kernel panic - not syncing:" 的消息,一旦 Systemd 開始運行,內核消息就會被捕捉到並寫入系統日誌。但是,當 Kernel panic 發生時,內核發出的診斷信息 幾乎不會 被寫入硬碟上的日誌文件,因為在 system-journald
運作前內核就死鎖了。因此,檢查內核崩潰消息的唯一方法是在崩潰時從控制台看錯誤信息(如果沒有設置 kdump crashkernel 的話)。可以用以下內核參數來啟動,這樣就能重現 tty1 上的錯誤信息:
systemd.journald.forward_to_console=1 console=tty1
pause_on_oops=seconds
內核參數。示例場景:模塊損壞
根據診斷信息,我們可以大致推斷出是哪個子系統或者模塊導致了崩潰。在這個示例中,我們假設機器在啟動時發生了 panic。注意那些用 粗體 標記的行:
kernel: BUG: unable to handle kernel NULL pointer dereference at (null) [1] kernel: IP: fw_core_init+0x18/0x1000 [firewire_core] [2] kernel: PGD 718d00067 kernel: P4D 718d00067 kernel: PUD 7b3611067 kernel: PMD 0 kernel: kernel: Oops: 0002 [#1] PREEMPT SMP kernel: Modules linked in: firewire_core(+) crc_itu_t cfg80211 rfkill ipt_REJECT nf_reject_ipv4 nf_log_ipv4 nf_log_common xt_LOG nf_conntrack_ipv4 ... [3] kernel: CPU: 6 PID: 1438 Comm: modprobe Tainted: P O 4.13.3-1-ARCH #1 kernel: Hardware name: Gigabyte Technology Co., Ltd. H97-D3H/H97-D3H-CF, BIOS F5 06/26/2014 kernel: task: ffff9c667abd9e00 task.stack: ffffb53b8db34000 kernel: RIP: 0010:fw_core_init+0x18/0x1000 [firewire_core] kernel: RSP: 0018:ffffb53b8db37c68 EFLAGS: 00010246 kernel: RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 kernel: RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffffffffc16d3af4 kernel: RBP: ffffb53b8db37c70 R08: 0000000000000000 R09: ffffffffae113e95 kernel: R10: ffffe93edfdb9680 R11: 0000000000000000 R12: ffffffffc16d9000 kernel: R13: ffff9c6729bf8f60 R14: ffffffffc16d5710 R15: ffff9c6736e55840 kernel: FS: 00007f301fc80b80(0000) GS:ffff9c675dd80000(0000) knlGS:0000000000000000 kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 kernel: CR2: 0000000000000000 CR3: 00000007c6456000 CR4: 00000000001406e0 kernel: Call Trace: kernel: do_one_initcall+0x50/0x190 [4] kernel: ? do_init_module+0x27/0x1f2 kernel: do_init_module+0x5f/0x1f2 kernel: load_module+0x23f3/0x2be0 kernel: SYSC_init_module+0x16b/0x1a0 kernel: ? SYSC_init_module+0x16b/0x1a0 kernel: SyS_init_module+0xe/0x10 kernel: entry_SYSCALL_64_fastpath+0x1a/0xa5 kernel: RIP: 0033:0x7f301f3a2a0a kernel: RSP: 002b:00007ffcabbd1998 EFLAGS: 00000246 ORIG_RAX: 00000000000000af kernel: RAX: ffffffffffffffda RBX: 0000000000c85a48 RCX: 00007f301f3a2a0a kernel: RDX: 000000000041aada RSI: 000000000001a738 RDI: 00007f301e7eb010 kernel: RBP: 0000000000c8a520 R08: 0000000000000001 R09: 0000000000000085 kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000c79208 kernel: R13: 0000000000c8b4d8 R14: 00007f301e7fffff R15: 0000000000000030 kernel: Code: <c7> 04 25 00 00 00 00 01 00 00 00 bb f4 ff ff ff e8 73 43 9c ec 48 kernel: RIP: fw_core_init+0x18/0x1000 [firewire_core] RSP: ffffb53b8db37c68 kernel: CR2: 0000000000000000 kernel: ---[ end trace 71f4306ea1238f17 ]--- kernel: Kernel panic - not syncing: Fatal exception [5] kernel: Kernel Offset: 0x80000000 from 0xffffffff810000000 (relocation range: 0xffffffff800000000-0xfffffffffbffffffff kernel: ---[ end Kernel panic - not syncing: Fatal exception
- [1] 表明了導致 panic 的錯誤類型。此處表示一個程序 bug。
- [2] 表明 panic 發生在 firewire_core 模塊中的 fw_core_init 函數中。
- [3] 表明 firewire_core 模塊是最後一個要加載的模塊。
- [4] 表明調用 fw_core_init 的函數是 do_one_initcall。
- [5] 表明這個 oops 消息事實上是一次 kernel panic 並且系統已經死鎖。
我們可以猜測,panic 發生在模塊 firewire_core 加載後的初始化例程中。(我們或許可以認為,由於程序錯誤,這台機器的火線 (IEEE 1394) 相關硬體與這一版本的驅動模塊不兼容,並且需要等待下一個版本的驅動發布)與此同時,讓機器運行起來的最簡單方法,就是不要加載這個模塊。我們可以通過以下兩種方式之一來完成這個操作:
- 如果這個模塊在加載 initramfs 時就會被加載,那就在重啟時加上內核參數
rd.blacklist=firewire_core
。 - 否則就用這個內核參數重啟
module_blacklist=firewire_core
。
重啟至 root shell 並修復故障
為了更改系統設置使得 panic 不再發生,你需要一個 root shell。如果 panic 發生在啟動時,有幾種方法可以在內核死鎖前獲得一個 root shell:
- 使用內核參數
emergency
、rd.emergency
或-b
重啟電腦,這樣可以在根文件系統掛載且systemd
啟動後就收到登錄提示符。
- 注意: 此時,根文件系統將會以只讀方式掛載。執行
# mount -o remount,rw /
來改變這一設置。
- 使用內核參數
rescue
、rd.rescue
、single
、s
、S
或1
在本地文件系統掛載完成後就得到登錄提示符。 - 使用內核參數
systemd.debug-shell=1
在 tty9 上獲得一個早期 root shell,然後按Ctrl-Alt-F9
切換到它。 - 通過使用不同的內核參數重新引導來嘗試禁用導致 panic 的內核功能。嘗試「備用參數」
acpi=off
和nolapic
。
- 提示:參閱 Linux 內核源碼樹中的
Documentation/admin-guide/kernel-parameters.txt
文件來查找所有內核參數。
- 作為最後的手段,你還可以使用 Arch Linux Installation CD 啟動電腦,把根文件系統掛載到
/mnt
,然後運行# arch-chroot /mnt
。
禁用導致 panic 的服務或程序,回滾有故障的更新或修復配置問題。
軟體包管理
參閱適用於一般主題的 Pacman#Troubleshooting,以及適用於 PGP 密鑰問題的 pacman/Package signing#Troubleshooting。
fuser
fuser 是一個用於識別進程占用的資源(如打開的文件、文件系統和 TCP/UDP 埠)的命令行工具。
fuser 由軟體包 psmisc包 提供,已經由 base包 組安裝。更多信息請查看 fuser(1)。
會話權限
/usr/lib/udev/rules.d/70-uaccess.rules
和 [2])首先,確保你有一個帶 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 -Fs libusb-0.1.so.4
extra/libusb-compat 0.1.5-1 usr/lib/libusb-0.1.so.4
在上述例子中,需要 安裝 軟體包 libusb-compat包。
這個錯誤也有可能意味著你用來安裝這個軟體的 PKGBUILD 裡沒有將這個共享庫作為它的依賴庫:如果來自官方源,請 報告一個 bug;如果來自 AUR,請在 AUR 網站相關頁面上把它報告給維護者。
錯誤信息: "file: could not find any magic files!"
如果看到這條消息,則可能表示軟體包更新破壞了動態連結程序的運行時依賴文件,並且系統現在已經基本癱瘓。在修復之前,你將無法重新編譯或重新安裝軟體包或重建 initramfs。
錯誤原因
某次軟體更新可能在 /etc/ld.so.conf.d
目錄中添加了非法的 filename.conf
文件,或是錯誤地編輯了 /etc/ld.so.conf
文件。其後果就是動態連結程序的運行時依賴文件 /etc/ld.so.cache
使用了錯誤的數據重新生成了。這可能導致系統中所有依賴共享庫的程序都出錯(即幾乎所有程序出錯)。
解決方法
- 使用 Arch Linux Installation CD 啟動。
- 掛載根文件系統
/
到/mnt
,掛載/boot
文件系統到/mnt/boot
,然後用命令# arch-chroot /mnt
切換到受損的系統中。 - 檢查
/etc/ld.so.conf
文件,刪除所有不正確的內容。 - 檢查放在
/etc/ld.so.conf.d/
目錄裡的文件,刪除所有不正確的文件。 - 使用命令
# ldconfig
重新生成動態連結程序的運行時依賴文件/etc/ld.so.cache
。 - 使用命令
# mkinitcpio -p linux
重新生成 Initramfs。 - 退出 chroot 環境,卸載文件系統,然後重啟到原來的系統中。
參閱
- Fix the Most Common Problems
- 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
- REISUB
- Debug Logging to a Serial Console on Freedesktop.org
- How to Isolate Linux ACPI Issues on Archive.org