HC620 使用 Btrfs zoned 時,如果檔案系統接近 100%,隨後突然只能讀取、不能寫入,最常見的線索確實是 ENOSPC、zone reclaim 沒有足夠工作空間,或者事務提交失敗後被核心強制切換為只讀。
但“寫滿”和“只讀”只能說明故障發生時的表象,不能直接證明硬碟沒有損壞。正確順序是:
- 立即停止寫入任務;
- 儲存故障發生時的核心日誌;
- 確認裝置、掛載狀態與 zoned 空間分佈;
- 區分純空間耗盡、回收受阻、事務中止和底層 I/O 錯誤;
- 只有證據支援純 ENOSPC 時,才嘗試重新以讀寫方式掛載並分批騰空間;
- 空間恢復後再做低風險整理和完整驗收。
不要一看到只讀就執行
mount -o remount,rw、全盤 balance 或btrfs check --repair。強制只讀是檔案系統的保護結果,先找出觸發它的第一條錯誤。
本文假設掛載點是 /mnt/hc620。裝置名僅用 /dev/sdX 表示,執行前必須替換成實際裝置或分割槽。不要照抄磁碟機代號。
為什麼 HC620 寫滿後比普通硬碟更難騰空間
Western Digital Ultrastar DC HC620 是 Host-Managed SMR,也就是由主機管理寫入區域的疊瓦盤。
Linux 通常把它暴露為 zoned block device:
|
|
預期能看到類似:
|
|
實際型號、容量顯示和裝置名可能不同,以本機輸出為準。
普通 CMR 硬碟可以在已分配扇區上覆蓋寫入。Host-Managed SMR 的順序寫 zone 則必須從當前寫指標繼續寫;要重新使用一個寫過的 zone,通常需要先搬走仍然有效的資料,再 reset 整個 zone。
Btrfs 從 Linux 5.12 起支援 zoned mode。它採用 COW,檔案覆蓋、後設資料更新或刪除後,舊資料塊可能不再被檔案系統引用,卻不會立刻變成可重新寫入的空 zone。
這些空間會在 btrfs filesystem usage 中顯示為:
|
|
它的含義不是“永久壞掉的硬碟容量”,而是過去寫過、現在已經沒有引用,但仍需經過 block group reclaim 和 zone reset 才能重新使用的空間。
回收過程需要把 zone 中仍有效的資料搬到新位置。如果已經沒有足夠的新 zone 可接收這些資料,就可能出現暫時性 ENOSPC。
因此,在 HC620 上:
|
|
不一定立即等於:
|
|
這也是 zoned Btrfs 真正寫到極限後,比普通盤更難現場處理的原因。
第一時間停止哪些任務
發現掛載點只讀後,不要反覆重試原來的複製任務。
先停止可能繼續製造 I/O 或日誌噪聲的服務,例如:
rsync、rclone或下載任務;- 容器和虛擬機器;
- 媒體庫掃描;
- 定時快照和備份;
- scrub、balance 或大規模刪除任務。
先確認當前是否有 balance 或 scrub:
|
|
不要為了執行本文命令而機械取消任務。先記錄狀態;如果 balance 或 scrub 正在執行並且系統仍有響應,應結合日誌判斷它是否就是故障現場的一部分。
檢視有哪些程序仍佔用掛載點:
|
|
這條命令只做觀察,不會自動終止程序。
先儲存故障日誌,再解除安裝或重啟
dmesg 中最有價值的往往不是最後一行 forced readonly,而是它之前最早出現的錯誤。
先儲存完整核心日誌到另一塊正常磁碟,例如系統盤:
|
|
再提取相關行:
|
|
如果機器已經重啟過,檢視上一次啟動:
|
|
如果系統沒有持久化 journal,上一次啟動的日誌可能不存在。因此故障現場應儘量先匯出日誌,再重啟。
同時儲存基本環境:
|
|
其中 findmnt 的 OPTIONS 如果包含 ro,只能確認當前掛載是隻讀,不能說明為什麼變成只讀。
確認裝置身份,禁止憑感覺填寫 /dev/sdX
先從掛載點反查源裝置:
|
|
再檢視檔案系統中的裝置:
|
|
確認穩定裝置連結:
|
|
如果檔案系統建在分割槽上,後續掛載必須使用該分割槽,而不是整盤。比如實際源裝置是 /dev/sda1,就不能寫成 /dev/sda。
把實際結果記錄為變數時,也要人工核對:
|
|
不要把示例中的中文佔位符原樣執行。
讀取 Btrfs 空間分佈
檔案系統仍處於掛載狀態時執行:
|
|
重點記錄:
|
|
典型的高風險組合類似:
|
|
不要只看 df -h。Btrfs 的資料、後設資料、system block group 和裝置未分配空間是不同層次;COW 還需要新的空間完成事務。
Device zone unusable 也不能單獨作為故障結論:
- 數值非零是 zoned COW 工作後的正常現象;
- 數值很大且
Device unallocated接近 0,才說明可回收空間與立即可分配空間嚴重錯位; - 數值在後臺回收期間可能變化;
- 即使它為 0,也不能排除後設資料耗盡或底層 I/O 錯誤。
檢查持久化裝置錯誤計數
執行:
|
|
正常輸出示例:
|
|
各項含義:
write_io_errs:下層塊裝置未能完成寫請求;read_io_errs:下層塊裝置未能完成讀請求;flush_io_errs:帶 FLUSH 的寫入失敗,關係到事務落盤順序;corruption_errs:發現校驗不匹配或損壞的後設資料頭;generation_errs:塊的 generation 與父節點期望不一致。
全為 0 是好跡象,但不是“硬碟一定健康”的證明。還要結合核心日誌、SMART、HBA 和鏈路錯誤判斷。
暫時不要使用:
|
|
-z 會在列印後清零計數。故障證據尚未儲存時清零,會丟失重要基線。
如果確實要觀察錯誤是否繼續增加,先儲存當前輸出,再記錄時間:
|
|
完成受控測試後再次比較,而不是隻看某一次快照。
用日誌把故障分成四類
第一類:純空間耗盡或臨時 ENOSPC
更支援這一類的證據包括:
|
|
同時滿足:
btrfs device stats沒有非零錯誤;- 日誌中沒有
I/O error; - 沒有 checksum、tree-checker、corrupt leaf 或 parent transid 錯誤;
- 檔案系統確實接近寫滿;
Device unallocated很少,或 zoned 回收明顯受限。
這種情況才適合進入後面的“受控讀寫掛載並騰空間”流程。
第二類:zone reclaim 或 block group 回收受阻
日誌可能出現:
|
|
此時問題不一定只是容量數字歸零,還可能涉及特定核心下的回收路徑、長時間鎖等待或 zoned 活躍 zone 限制。
不要在這時追加全盤 balance。先保留呼叫棧、核心版本和完整日誌,再參考站內的真實故障覆盤:
HC620 上 Btrfs zoned 兩次故障覆盤:鎖死、只讀與核心排查
第三類:事務中止,但原因尚未確定
下面幾行只說明結果:
|
|
真正原因通常在前面。要向上查幾十到幾百行,找到第一條錯誤、返回碼和呼叫棧。
不能把所有 transaction aborted 都歸類成寫滿。底層寫失敗、後設資料驗證失敗和核心缺陷同樣可能中止事務。
第四類:I/O、校驗或結構錯誤
出現以下任一線索,應停止“刪點檔案就能修好”的流程:
|
|
這時優先保護資料副本,檢查磁碟、SAS/SATA HBA、線材、供電和核心 zoned 錯誤。不要把裝置計數非零簡單解釋為“只是滿盤”。
先做只讀掛載與資料搶救
如果當前掛載還能讀,先複製最重要且沒有其他副本的資料。
若需要解除安裝後重新掛載,先退出佔用目錄的 shell,再執行:
|
|
確認已經解除安裝:
|
|
沒有輸出才表示該掛載點不在當前掛載表中。
先以只讀方式掛載:
|
|
然後複製重要檔案到另一塊健康磁碟。只讀搶救時不要把目標目錄放回 HC620 本身。
如果普通只讀掛載失敗,不要隨機疊加 rescue= 引數。不同錯誤需要不同救援選項,錯誤引數可能掩蓋日誌或改變讀取結果,應根據具體報錯再決定。
什麼時候才允許嘗試重新讀寫掛載
同時滿足以下條件時,可以考慮一次受控嘗試:
- 已儲存故障日誌;
- 重要資料有其他副本,或已先完成只讀搶救;
- 日誌的第一原因明確指向
ENOSPC; - 沒有 I/O、校驗、tree-checker 或 zone write pointer 錯誤;
btrfs device stats沒有異常計數;- 沒有卡住的舊核心任務;
- 檔案系統可以乾淨解除安裝。
先解除安裝只讀掛載:
|
|
再做一次普通掛載,不使用 remount,rw 強頂當前錯誤狀態:
|
|
立即驗證:
|
|
如果掛載選項仍然包含 ro,或者日誌再次出現事務中止,停止嘗試,不要迴圈解除安裝、掛載。
如果成功顯示 rw,也不要馬上恢復複製服務。讀寫視窗的第一個任務是分批釋放已知可刪除的資料。
讀寫恢復後怎樣安全騰空間
優先選擇已經確認有其他副本、可以重建、並且體積大的目錄。
先檢視一級目錄大小:
|
|
不要直接照抄:
|
|
應先列印真實目標,確認沒有變數展開錯誤:
|
|
確認目標正確後再刪除:
|
|
對於多 TB 資料,建議按獨立子目錄或批次刪除,不要同時進行大規模寫入。
每批後檢查:
|
|
btrfs filesystem sync 可能需要一段時間。命令返回前不要把“目錄消失”誤當成空間已經完成回收。
應先以釋放數百 GiB 的量級為目標,而不是隻刪幾 GiB 後馬上繼續灌滿。具體安全餘量取決於工作負載、zone 大小、後設資料和回收效率,不能給所有 HC620 一個絕對比例。
長期使用中,不建議把 zoned Btrfs 維持在 99%~100%。要同時預留:
- 日常新寫入空間;
- COW 事務空間;
- 後設資料增長空間;
- zone reclaim 搬運仍有效資料的工作空間;
- 應急刪除和維護視窗。
刪除後為什麼空間可能沒有立即回來
刪除檔案主要解除引用並更新後設資料。對於 zoned 裝置,相關 zone 裡可能還有有效 extent,Btrfs 必須先遷走它們,才能 reset zone。
因此可能看到:
- 檔案已經刪除;
Used有所下降;Device zone unusable暫時上升;Device unallocated沒有按刪除量同步增加;- 後臺 cleaner 繼續產生 I/O。
這不一定表示刪除失敗。觀察一段完整的受控回收週期,並以日誌和 btrfs filesystem usage -T 的趨勢判斷。
如果數值長期不變化,同時出現 cleaner 阻塞、事務錯誤或 D 狀態任務,就應按回收路徑故障處理,而不是繼續大量刪除。
balance 只能在空間恢復後逐步執行
balance 會搬移 block group。大多數 balance 操作需要先建立新的 block group 作為工作空間,因此滿盤時直接執行無過濾器的 balance 可能再次觸發 ENOSPC。
不要一上來執行:
|
|
先確認當前沒有 balance:
|
|
在日誌穩定、已經釋放空間、裝置錯誤計數沒有增長的前提下,可以先處理完全未使用的 block group:
|
|
usage=0 不需要額外工作空間,是 Btrfs 官方文件針對 ENOSPC 給出的低風險起點。
完成後檢查:
|
|
只有空間和日誌都穩定時,才考慮低閾值:
|
|
再次觀察後,才可能提高到:
|
|
這些數字不是必須逐級執行的固定處方。閾值越高,可能搬移的資料越多,所需工作空間和 I/O 也越大。
如果之前已經出現 btrfs-cleaner、block group 刪除或 zone finish 路徑卡死,不要把 balance 當成自動修復。它可能重新進入相近程式碼路徑,應先查清核心問題。
不要在故障盤上做的操作
不要強制 remount 為讀寫
避免:
|
|
如果核心剛剛因為錯誤把檔案系統強制只讀,直接 remount 會跳過“儲存日誌、解除安裝、重新評估”的邊界,而且通常不能消除導致只讀的根因。
不要盲目執行全盤 balance
避免:
|
|
滿盤 balance 需要搬移資料,可能比原故障需要更多臨時空間。
不要執行 btrfs check --repair
避免:
|
|
Btrfs 官方文件明確警告:除非得到開發者或有經驗人員針對具體錯誤的建議,否則不要使用 --repair。
如果確實需要離線結構檢查,必須先解除安裝,並預設使用只讀模式:
|
|
但對 14TB 或 15TB 檔案系統,這項檢查可能耗時很長、佔用大量記憶體併產生持續讀取。只有純 ENOSPC 證據時,通常不需要把它當作第一步。
不要先清零裝置錯誤統計
避免在儲存證據前執行:
|
|
清零不會修復硬碟、線材或 HBA,只會抹掉比較基線。
不要繼續邊刪邊寫
Host-Managed SMR 上數 TB 刪除、zone reclaim 和數 TB 新寫入重疊,會顯著擴大故障面。
更穩妥的流程是:
|
|
空間恢復後的驗收
恢復 rw 只是開始,不能作為最終成功標準。
驗證掛載狀態
|
|
確認:
- 源裝置正確;
- 檔案系統為
btrfs; - 掛載選項包含
rw; - 沒有掛錯子卷或分割槽。
驗證空間分佈
|
|
不要只追求 Device zone unusable 歸零。更重要的是:
- 已經有足夠可用空間;
Device unallocated或可分配空間恢復;- 後設資料不再逼近極限;
- 回收過程中沒有新錯誤。
驗證錯誤計數沒有增長
|
|
與故障後儲存的基線比較。如果 write_io_errs、flush_io_errs、corruption_errs 或 generation_errs 增長,停止恢復大規模寫入。
驗證核心沒有再次強制只讀
|
|
關注新產生的日誌,不要把幾小時前的舊錯誤誤判為剛剛復發。
做小規模寫入測試
先寫到一個明確的測試目錄:
|
|
刪除測試檔案並再次提交:
|
|
隨後再次檢查日誌、空間和裝置統計。
1GiB 測試透過只能證明小規模寫入成功,不能證明數 TB 持續寫入一定穩定。正式任務應從小批次恢復,並保留監控。
有冗餘或備份後再安排 scrub
scrub 會讀取全部已分配資料並驗證校驗和,可能持續很久。不要在剛恢復的滿盤上立刻與 balance、複製和刪除同時執行。
確認檔案系統穩定且重要資料有副本後,再安排獨立維護視窗:
|
|
完成後檢視:
|
|
單盤 single 資料沒有另一份映象可供 Btrfs 自動修復。scrub 能發現校驗問題,不等於一定能修復。
長期避免再次寫滿的做法
給寫入任務設定容量停止線
不要讓備份指令碼只看命令退出碼。寫入前後都記錄:
|
|
當可用空間低於你的維護閾值時,停止接收新資料並告警。
閾值不應只按“還能放下下一個檔案”計算,還要包含 COW、後設資料和 zone reclaim 的空間。
把大量刪除和大量寫入錯開
推薦:
|
|
不要安排 rsync、快照刪除、scrub 和 balance 在同一個維護視窗中爭搶 I/O。
對歸檔資料保留外部清單
可為重要目錄生成校驗清單,並把清單複製到另一塊磁碟:
|
|
檔名中包含換行符時,上面的文字清單格式仍可能不便處理;如果資料來源會產生特殊檔名,應使用支援 NUL 分隔的專用清單流程。
不把單盤檔案系統當成備份
Btrfs 校驗和能發現靜默損壞,但單盤資料 profile 通常沒有第二份資料副本可恢復。
HC620 上的資料至少還應有:
- 另一塊本地磁碟副本;
- 另一臺機器或異地副本;
- 可定期驗證的物件儲存或離線副本。
常見問題
Device zone unusable 很大,是否說明盤壞了
不一定。它表示過去寫過、現在因 COW 不再被引用、但尚未經過回收和 zone reset 的空間。
應同時看 Device unallocated、資料與後設資料使用率、核心日誌、回收趨勢和裝置錯誤計數。
刪除檔案後能馬上恢復同等容量嗎
不能保證。刪除先改變檔案系統引用,底層 zone 還可能需要搬移有效資料並 reset。
正常重新掛載成功,是否就能繼續寫滿
不能。應先騰出明顯餘量,確認日誌和錯誤計數穩定,再做小規模測試,最後分批恢復業務。
write_io_errs 為 0,是否排除硬碟問題
不能完全排除。它只說明 Btrfs 記錄的該類持久化計數沒有寫失敗;還要檢查核心塊層日誌、SMART、HBA、線材和供電。
可以使用 mount -o recovery 嗎
不要把舊教程裡的 recovery 當成通用修復開關。當前 Btrfs 的救援掛載選項有明確適用錯誤,而且通常要求只讀掛載,應根據實際日誌選擇。
為什麼 df 顯示還有空間卻報 ENOSPC
Btrfs 的 COW、資料與後設資料 block group、事務預留和 zoned 回收都需要空間。df 展示的檔案級可用估算不能完整表達這些內部約束。
要不要把後設資料從 DUP 改成 single
不要僅為了擠出空間就臨時改變 profile。profile 轉換本身要搬移 block group,需要工作空間和大量 I/O;zoned 模式支援的 profile 還受核心與工具版本約束。
usage=0 balance 為什麼相對安全
因為它只掃描並回收完全未使用的 block group,官方文件說明該過濾器不需要額外工作空間。
“相對安全”仍不等於適合所有故障。如果日誌顯示回收路徑卡死或結構錯誤,先停止並分析。
能否直接斷電重啟
如果系統仍有響應,應先儲存日誌、停止任務、等待必要事務並正常解除安裝。強制斷電會增加未提交寫入和故障分析的不確定性。
如果核心任務長時間處於不可中斷 D 狀態、機器無法正常關機,應先透過另一臺機器或遠端控制檯儲存儘可能多的日誌,再評估重啟風險。
一份可執行的故障清單
按順序執行,不要跳到 balance 或 repair:
|
|
需要收集哪些輸出才能繼續判斷
如果仍無法確認屬於哪一類,收集以下輸出時隱藏序列號等敏感資訊,但不要刪掉錯誤上下文:
|
|
根據這些輸出,通常可以把下一步收斂到:
- 單純寫滿,可以受控騰空間;
- zone reclaim 沒有工作空間或回收路徑阻塞;
- Btrfs 事務中止,需要追溯首條錯誤;
- HC620、HBA、線材或供電出現真實 I/O 故障;
- 檔案系統出現校驗或結構錯誤,需要先搶救資料再由有經驗人員處理。
參考資料
- Western Digital Ultrastar DC HC620 Data Sheet
- Btrfs 官方文件:Zoned mode
- Btrfs 官方文件:btrfs-filesystem
- Btrfs 官方文件:btrfs-balance
- Btrfs 官方文件:btrfs-device
- Btrfs 官方文件:btrfs-check
HC620 寫滿後變只讀,最重要的不是儘快讓它重新顯示 rw,而是先判斷核心為什麼保護性只讀。只有證據明確支援純 ENOSPC,才應在儲存日誌和資料副本後受控騰空間;一旦出現 I/O、校驗、結構或 zone write pointer 錯誤,就應停止寫入,把工作重點轉向資料搶救和硬體鏈路排查。