Raspberry Pi 5 外接 USB SSD 無故凍死:RTL9210B + UAS 掉線的定位與修復

我有一台 Raspberry Pi 5,root 檔案系統跑在一顆外接 USB SSD 上,平常掛著一個常駐的 web 服務。某天它突然「連不上」——SSH、網頁全都沒反應,只能手動拔電重開。這篇記錄我怎麼一步步把原因鎖定到外接 SSD 的 USB 橋接晶片,以及最後怎麼修。

現象

  • 服務與 SSH 全部無回應,整台機器像從網路上消失。
  • 沒有任何預警,重開機後一切又正常。
  • 直覺會以為是「網路斷線」,但事實不是。

第一步:這是斷線,還是整台凍死?

關鍵證據在系統日誌。先看上一次開機(-1)的日誌尾端:

1
journalctl -b -1 --no-pager | tail -60

結果日誌在 20:12:30 戛然而止,停在服務每隔幾秒一次的正常輪詢中間,之後直到我手動重開(約 47 分鐘後)完全空白。再對照開關機記錄:

1
last -x reboot shutdown | head

兩次開機之間沒有 shutdown 記錄——代表系統不是正常關機,是被硬斷電的。

這兩點合起來說明:不是網路掉線,也不是單一服務崩潰(那樣其他服務還會繼續寫日誌),而是 journald 本身都停止寫入 = 整個作業系統凍死(hard freeze),所以才會「連不上」。

第二步:逐一排除常見死因

Pi 當機最常見的幾個原因,用日誌與現場狀態逐一排除:

嫌疑 檢查方式 結果
欠壓 / 電源不穩 vcgencmd get_throttled、journal 搜尋 under-voltage 0x0,全程無記錄 ❌
過熱降頻 vcgencmd measure_temp ~60°C,無 thermal throttle ❌
記憶體耗盡(OOM) journal 搜尋 oom-kill 記憶體充足、swap 沒動 ❌
Kernel panic / soft-lockup / RCU stall journalctl -b -1 -k 搜尋 完全沒有 ❌
磁碟寫滿 df -h / 只用 29% ❌
SSD 硬體故障 smartctl -H /dev/sda PASSED(碟本身健康)❌

軟體、電源、溫度、記憶體、磁碟空間、硬碟健康——全部排除。一個「什麼都沒記錄到」的完全凍死,開始把矛頭指向底層硬體。

第三步:鎖定根因

先看 root 到底掛在什麼裝置上:

1
2
lsblk -o NAME,SIZE,TYPE,TRAN,MODEL,MOUNTPOINT
lsusb

答案是:root(/dev/sda2)在一顆外接 USB SSD 上,透過 Realtek RTL9210B-CG(USB id 0bda:9210,一顆 M.2 NVMe → USB 橋接晶片)連接,且目前綁在 uas 驅動(USB Attached SCSI)上。

再看 USB 連結的健康狀況,兩次開機都各有幾筆:

1
2
usb 2-1: Enable of device-initiated U1 failed.
usb 2-1: Enable of device-initiated U2 failed.

這是這顆橋接晶片 USB3 連結電源狀態(LPM)協商不良的訊號。

RTL9210 / RTL9210B + UAS + Pi 是社群裡惡名昭彰的組合:這顆橋接在 UAS 模式下、連結不穩時會突然從 USB 匯流排掉線。而因為 root 就在這顆碟上,一旦碟消失,kernel 連日誌都寫不進去(記錄目標沒了),整台機器瞬間凍住、網路全死,只能硬斷電——這正好完美對上我們看到的指紋。

誠實說一句:因為是「凍死」,當下那一刻按定義寫不出任何 log,所以不存在一行「鐵證日誌」。以上是「排除法 + 硬體指紋 + 前後的 U1/U2 失敗」三者共同指向的高信心結論。

修復:停用這顆橋接的 UAS

最簡單有效的做法,是針對這顆橋接停用 UAS,退回較保守但穩定的 BOT(Bulk-Only Transport)模式。在 /boot/firmware/cmdline.txt(必須維持單行)結尾加上:

1
usb-storage.quirks=0bda:9210:u

0bda:9210 是這顆橋接的 vid:pid,:u 代表對它停用 UAS。改完重開機生效。

修改前務必備份(root 在這顆碟上,動開機參數要小心):

1
sudo cp -a /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak-$(date +%Y%m%d-%H%M%S)

重開機後驗證是否生效:

1
2
3
# 驅動應該從 uas 換成 usb-storage
ls /sys/bus/usb/drivers/uas/ # 應該沒有裝置
dmesg | grep -iE "UAS is ignored|Quirks match"

看到這兩行就對了:

1
2
usb 2-1: UAS is ignored for this device, using usb-storage instead
usb-storage 2-1:1.0: Quirks match for vid 0bda pid 9210: 800000

效能代價:實測 UAS vs BOT

停用 UAS 一定有代價,但到底掉多少?我用 fio 在改動前後各跑一次相同測試(測試檔寫在真正的 SSD 上、--direct=1 繞過 cache):

測項 UAS(前) BOT(後) 變化
循序讀 (1M, QD16) 389 MB/s 373 MB/s −4%
循序寫 (1M, QD16) 360 MB/s 349 MB/s −3%
隨機讀 4K QD32 32.4k IOPS 6.5k IOPS −80%
隨機寫 4K QD32 34.8k IOPS 7.4k IOPS −79%
隨機讀 4K QD1 6,302 IOPS 6,378 IOPS ~持平

解讀:

  • 循序讀寫幾乎無損(−3~4%):開機、複製大檔、備份完全無感。
  • QD1(一次一條操作)完全沒變:單執行緒、延遲受限的存取不受影響。
  • 深佇列隨機 IOPS 掉約 80%:這就是 UAS 指令佇列消失的代價。注意 BOT 的 QD32 成績幾乎等於它自己的 QD1——證明 BOT 把並發請求序列化成一次一條了。

換句話說,只有在「大量小 I/O 同時打」的場景(例如高並發資料庫)才會明顯感覺到。對低並發、以序列小讀寫為主的服務來說,日常幾乎無感。拿深佇列隨機 IOPS 換「不再整台凍死、不用拔電」,對一台要穩定常駐的機器絕對划算。

完整的測試腳本與原始數據我一併放在本文同目錄:ssd_bench.sh、bench_uas_baseline.txt、bench_bot_after.txt。

更徹底的方案

如果很在意那 80% 的隨機 IOPS,或掉線仍偶發,最終解是把 M.2 NVMe 從 USB 轉接盒移到 Pi 5 官方的 NVMe HAT,走原生 PCIe,完全繞開 USB 橋接——穩定性與速度兩者都贏,隨機效能不但拿回來還更快。

加一層監控

修完不能只靠「感覺沒再當」。我寫了一個小腳本掛 cron 每 5 分鐘檢查一次:SSD 溫度(smartctl -A)、SoC 溫度與 throttle 旗標(vcgencmd)、SMART 健康、以及最近的 kernel USB/儲存錯誤(掉線的前兆),任何異常就在日誌標上 [WARN] / [ALERT]:

1
*/5 * * * * ~/ssd_monitor.sh >/dev/null 2>&1

正常時每行長這樣,之後要回頭查有沒有過熱或掉線,grep 一下 WARN/ALERT 即可:

1
2026-08-22 21:32:44 [OK] ssd=36C soc=59.8C throttled=0x0 health=PASSED drv=usb-storage

小結

  1. 先分清楚是「斷線」還是「凍死」:看 journald 是否整個停止寫入、有沒有 shutdown 記錄,比什麼都關鍵。
  2. 用排除法縮小範圍:電源、溫度、OOM、panic、磁碟、SMART 一輪掃過。
  3. root 在外接 USB SSD 上時,橋接晶片掉線會拖垮整台機器——RTL9210 + UAS 是已知雷區,usb-storage.quirks=<vid>:<pid>:u 是便宜有效的解法。
  4. 代價心裡有數:循序幾乎無損,深佇列隨機 IOPS 是主要犧牲;真要效能就上 NVMe HAT。
  5. 修完補上監控,用數據確認問題真的走了。