出自 Arch Linux 中文维基

本文介紹了一些常規的故障排除方法。有關特定應用程式的問題,請參閱該特定程序的 wiki 頁面。

常用手段

注意細節

為了解決遇到的問題,對當前使用的這個程序,你應該有一個基本的了解,這是 至關重要 的。它是如何工作的,它依賴什麼才能正常運行?如果不能很好地回答這些問題,最好閱讀一下這些出錯程序的 Archwiki 文章。一旦你覺得你已經理解了它,你將更容易找出問題的原因。

常見問題 / 檢查項

下面列出了許多常見問題,用於排查故障。在每個問題下都有注釋,說明你該如何回答這個問題,緊接著的是一些如何收集數據的簡單示例,還有查看各種日誌的工具。

  1. 出現了什麼故障?
    請儘可能精確地描述問題,這將幫助你在查找特定信息的時候不至感到困惑或扯到別的方面去。
  2. 是否顯示了錯誤信息?(如果有的話)
    將包含相關 錯誤信息完整輸出 複製並粘貼到類似 $HOME/issue.log 這樣單獨的文件中。例如,可以將以下 mkinitcpio 命令的輸出轉發到 $HOME/issue.log
    $ mkinitcpio -p linux >> $HOME/issue.log
  3. 可以復現這個故障碼?
    如果是這樣,請 按步驟 給出 確切的 指示/命令來做到這一點。
  4. 第一次遇到這些故障的時間,以及從沒有故障到故障發生之間你修改了什麼內容?
    如果這種情況發生在某次升級之後,可以列出 所有已升級的包。包括 版本號,同時粘貼 pacman.log (/var/log/pacman.log) 的升級日誌。使用 systemd 的 systemctl 工具檢查故障程序依賴的 所有 服務的運行狀態。例如,可以將 systemd 命令的輸出轉發到 $HOME/issue.log
    $ systemctl status dhcpcd@eth0.service >> $HOME/issue.log
    注意: 使用 >> 可以保證 $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)。你可以 安裝 pbpstAURgist 來自動上傳信息。例如,要上傳這次啟動以來的 systemd 日誌,可以這麼做:

# journalctl -xb | pbpst -S

這將返回一個連結,你可以把它貼到論壇或 IRC。

另外,在提問之前,請先閱讀 提問的智慧行為準則

系統啟動問題

診斷 啟動過程 中的問題主要是修改 內核參數,然後重啟系統。

如果系統無法啟動,可以從 live 鏡像 啟動並 chroot 到現有系統。

控制台的輸出信息

在啟動過程完成以後,屏幕會被清空並顯示登錄提示符,這使得用戶無法看到初始化過程中的輸出和其中的錯誤信息。這一默認特性可以使用接下來幾節中的方法進行修改。

請注意,無論選擇下面哪個方法,在啟動後通過使用 dmesgjournalctl -b 都可以顯示內核消息,用於檢查錯誤。

輸出流控制

以下是適用於大多數終端模擬器的基本操作,包括虛擬終端 (vc):

  • Ctrl+S 暫停輸出
  • Ctrl+Q 繼續輸出

這樣不僅會暫停輸出,而且會暫停嘗試列印到終端的程序,即暫停輸出時會阻塞 write() 調用。 如果你的 init 進程出現凍結,請確保系統控制台沒有暫停。

要查看已經顯示過的錯誤信息,參見 Getty#將引導消息保留在 tty1 上

回滾顯示

回滾顯示允許用戶查看已經從控制台滾動過去並消失的文字內容。這通常是在視頻適配器和顯示設備之間創建緩衝(稱為回滾緩衝區)實現的。默認情況下,將緩衝的內容上下滾動的快捷鍵是 Shift+PageUpShift+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_debugsched_debug。更多詳細信息請參考 kernel parameter documentation

注意: 如果無法回滾的足夠遠以查看所需的啟動輸出,你需要擴大 回滾緩衝區 的大小。

故障恢復控制台

在啟動過程中的某個階段獲取一個交互式 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 而帶來安全風險。

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(主線)版本的內核(比如官方倉庫提供的內核)不會經常發生內核崩潰,但是當它們發生時,你需要知道如何處理它們。

注意: Kernel panics 有時被稱為 oopsKernel oops,雖然 panics 和 oops 都是在出錯的狀態下才會發生,但是 oops 更為通用,因為它並不一定會導致內核死鎖,有時內核可以通過結束出錯的任務來恢復並繼續運行。
提示:在啟動時傳遞參數 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:

  • 使用內核參數 emergencyrd.emergency-b 重啟電腦,這樣可以在根文件系統掛載且 systemd 啟動後就收到登錄提示符。
注意: 此時,根文件系統將會以只讀方式掛載。執行 # mount -o remount,rw / 來改變這一設置。
  • 使用內核參數 rescuerd.rescuesinglesS1 在本地文件系統掛載完成後就得到登錄提示符。
  • 使用內核參數 systemd.debug-shell=1 在 tty9 上獲得一個早期 root shell,然後按 Ctrl-Alt-F9 切換到它。
  • 通過使用不同的內核參數重新引導來嘗試禁用導致 panic 的內核功能。嘗試「備用參數」 acpi=offnolapic
提示:參閱 Linux 內核源碼樹中的 Documentation/admin-guide/kernel-parameters.txt 文件來查找所有內核參數。
  • 作為最後的手段,你還可以使用 Arch Linux Installation CD 啟動電腦,把根文件系統掛載到 /mnt,然後運行 # arch-chroot /mnt

禁用導致 panic 的服務或程序,回滾有故障的更新或修復配置問題。

軟體包管理

參閱適用於一般主題的 Pacman#Troubleshooting,以及適用於 PGP 密鑰問題的 pacman/Package signing#Troubleshooting

fuser

Tango-view-fullscreen.png這篇文章的某些內容需要擴充。Tango-view-fullscreen.png

原因: 需要更多關於其用法的信息 (在 Talk:常規故障排除 中討論)

fuser 是一個用於識別進程占用的資源(如打開的文件、文件系統和 TCP/UDP 埠)的命令行工具。

fuser 由軟體包 psmisc 提供,已經由 base 組安裝。更多信息請查看 fuser(1)

會話權限

注意: 你必須使用 systemd 作為你的 init 進程,本地會話才能正常工作。[1] 它是各種設備的 polkit 權限和 ACL 所必需的 (參見 /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"

Tango-inaccurate.png本文或本章節的事實準確性存在爭議。Tango-inaccurate.png

原因:soname bump 之後相關程序可能需要重新編譯。(在 Talk:常規故障排除 中討論)


如果在運行程序時遇到類似於這樣的錯誤:

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

使用 pacmanpkgfile 來查找包含丟失共享庫的軟體包:

$ 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 使用了錯誤的數據重新生成了。這可能導致系統中所有依賴共享庫的程序都出錯(即幾乎所有程序出錯)。

解決方法

  1. 使用 Arch Linux Installation CD 啟動。
  2. 掛載根文件系統 //mnt,掛載 /boot 文件系統到 /mnt/boot,然後用命令 # arch-chroot /mnt 切換到受損的系統中。
  3. 檢查 /etc/ld.so.conf 文件,刪除所有不正確的內容。
  4. 檢查放在 /etc/ld.so.conf.d/ 目錄裡的文件,刪除所有不正確的文件。
  5. 使用命令 # ldconfig 重新生成動態連結程序的運行時依賴文件 /etc/ld.so.cache
  6. 使用命令 # mkinitcpio -p linux 重新生成 Initramfs
  7. 退出 chroot 環境,卸載文件系統,然後重啟到原來的系統中。

參閱