Btrfs Scrub 使用指南:資料校驗、自動修復與定期巡檢

整理 Btrfs scrub 的作用、命令用法、自動修復條件、NOCOW 檔案風險、唯讀 scrub 注意事項、定期巡檢週期和頻寬限制方法。

Btrfs scrub 是 Btrfs 日常維護裡最重要、也最容易被誤解的功能之一。它不是傳統意義上的 fsck,而是一種線上校驗流程:讀取檔案系統中的資料和 metadata,驗證校驗和、superblock、metadata block header 以及磁碟讀取錯誤,並在有可靠副本時嘗試修復損壞。

如果你的 Btrfs 用在 NAS、家用伺服器、備份碟或多碟陣列上,scrub 應該成為定期巡檢的一部分。它的價值不是「等出事再修」,而是在磁碟還能讀、陣列還有好副本的時候,盡早發現靜默損壞。

scrub 到底檢查什麼

根據 Btrfs 官方文件,scrub 會遍歷檔案系統資料和 metadata,主要檢查:

  • 資料區塊校驗和錯誤。
  • 基礎 super block 錯誤。
  • 基礎 metadata block header 錯誤。
  • 磁碟讀取錯誤。

在使用複製型 block group profile 的檔案系統上,例如 RAID1,讀寫掛載下的 scrub 可以自動修復部分損壞。修復方式不是「憑空恢復」,而是從另一個已驗證正確的副本複製好資料回來。

這點很關鍵:scrub 的修復能力依賴「存在可用的好副本」。如果單碟上只有一份資料,scrub 可以發現校驗錯誤,但通常無法自行恢復原始內容。

常用命令

對掛載點啟動 scrub:

1
sudo btrfs scrub start /

以前台方式執行,適合手動觀察結果:

1
sudo btrfs scrub start -B /

查看狀態:

1
sudo btrfs scrub status /

取消正在執行的 scrub:

1
sudo btrfs scrub cancel /

恢復被中斷的 scrub:

1
sudo btrfs scrub resume /

如果指定的是 Btrfs 掛載路徑,Btrfs 會平行 scrub 該檔案系統裡的所有裝置。如果指定的是某個裝置,則只 scrub 該裝置;但當指定裝置上的副本讀取或校驗失敗時,Btrfs 仍會嘗試從其他裝置讀取好副本。

scrub 不是 fsck

這是最容易踩坑的地方。scrub 不是 btrfs check,也不是傳統意義上的檔案系統檢查器。

scrub 能做的是:

  • 利用校驗和發現資料或 metadata 損壞。
  • 在有其他可靠副本時自動修復。
  • 發現磁碟讀取錯誤和部分基礎結構錯誤。

scrub 不能做的是:

  • 重建沒有好副本的資料。
  • 替代離線檔案系統檢查。
  • 修復所有複雜的樹結構損壞。
  • 保證應用層檔案內容一定正確。

如果檔案系統結構已經嚴重損壞,通常需要在專家指導下使用 btrfs check 等工具。不要把 scrub 當成「萬能修復命令」。

NOCOW 檔案的風險

Btrfs 官方文件特別提醒:對檔案設定 NOCOW 屬性,也就是常見的 chattr +C,目前實作中會隱式啟用 NODATASUM。這意味著這些檔案的資料本身沒有校驗和。

scrub 仍然可以校驗和修復這些檔案的 metadata,但不能校驗檔案資料內容。問題在多副本場景裡尤其明顯:如果某個 NOCOW 檔案的一個副本壞了,Btrfs 沒有資料校驗和判斷哪個副本是好的,就可能把壞內容返回給使用者空間工具。

需要特別注意的是,一些軟體會預設使用 +C 來提升效能。例如 systemd journal 和部分 libvirt 儲存池場景可能會設定 NOCOW。對於虛擬機映像、資料庫、日誌目錄,這種做法有效能理由,但也意味著你不能期待 scrub 像保護普通 COW 檔案那樣保護它們的資料內容。

唯讀 scrub 也可能寫入

另一個反直覺點是:在讀寫掛載的檔案系統上執行 read-only scrub,仍然可能導致一些寫入。

官方文件說明,這是為了避免 block group 標記唯讀和寫回 block group items 之間的競態。換句話說,如果你希望 scrub 過程中完全沒有寫入,就需要在唯讀掛載的檔案系統上執行唯讀 scrub,而不是在讀寫掛載上加一個唯讀 scrub 選項就完事。

對普通使用者來說,這意味著:

  • 日常線上 scrub 可以在讀寫掛載上執行。
  • 如果你在做取證、故障分析或極度保守的唯讀檢查,要先明確掛載狀態。
  • 不要把 read-only scrub 誤解成絕對零寫入。

中斷與恢復

新內核中,scrub 可能被多種事件中斷,例如系統掛起/休眠、檔案系統凍結、cgroup freezing、pending signals 等。被中斷後,正在執行的 scrub 會取消,但可以透過 btrfs scrub resume 從保存的位置繼續。

scrub 狀態會記錄在:

1
/var/lib/btrfs/

檔案名通常類似:

1
2
scrub.status.UUID
scrub.progress.UUID

狀態檔案會定期更新。恢復 scrub 時,會從最後保存的位置繼續,而不是完全從頭再來。

建議多久跑一次

官方建議的週期是每月一次,實際可以根據資料重要性和磁碟狀態調整。

比較常見的安排是:

  • 家用 NAS:每月一次。
  • 備份碟:每次長期接入後或每月一次。
  • 重要多碟陣列:每月一次,必要時更頻繁。
  • 新碟遷移或懷疑壞碟:遷移後立即跑一次。

scrub 在空閒檔案系統上的裝置頻寬利用率可能接近 80%,所以不要在業務高峰期跑。對機械碟陣列,scrub 期間延遲可能明顯升高;對 SSD,也會增加讀放大和後台壓力。

限制 scrub 頻寬

過去可以用 ionice 嘗試降低 scrub 對前台 I/O 的影響,但官方文件提醒,並不是所有 I/O 調度器都支援這種方式。CFQ 已經不再是主流;BFQ 支援相關優先級,但使用前應先理解其行為。對 mq-deadline 等常見調度器,更推薦使用 cgroup2 I/O controller 或 Btrfs 自帶的限速介面。

使用 systemd 限制讀取頻寬的例子:

1
sudo systemd-run -p "IOReadBandwidthMax=/dev/sdx 10M" btrfs scrub start -B /

Linux 5.14 以後,可以透過 Btrfs 專用 sysfs 介面設定每裝置 scrub 限速:

1
echo 100m | sudo tee /sys/fs/btrfs/FSID/devinfo/DEVID/scrub_speed_max

查看目前限制:

1
sudo btrfs scrub limit /

注意這個設定不是永久的,檔案系統卸載後會失效。實際路徑裡的 FSIDDEVID 要按你的系統替換,可以先查看:

1
2
sudo btrfs filesystem show /
ls /sys/fs/btrfs/

實用維護流程

一個比較穩妥的 Btrfs 巡檢流程可以是:

1
2
3
4
sudo btrfs scrub start -B /
sudo btrfs scrub status /
sudo btrfs device stats /
dmesg -T | grep -Ei "btrfs|checksum|i/o error|read error"

如果 scrub 報告有 corrected errors,說明已經從好副本修復過資料,但這不代表可以忽略。你應該繼續檢查磁碟 SMART、線材、電源、控制器和 Btrfs device stats。

如果 scrub 報告 uncorrectable errors,說明 Btrfs 找不到可用好副本,必須盡快備份仍能讀取的資料,定位具體檔案或裝置,並根據情況替換硬碟或從備份恢復。

總結

Btrfs scrub 的定位很明確:它是線上資料巡檢和副本修復工具,不是 fsck,也不是備份。

它最適合用在有校驗和、有冗餘副本的 Btrfs 檔案系統上,定期發現靜默損壞並自動從好副本恢復。它不能保護沒有校驗和的 NOCOW 檔案資料,也不能在沒有好副本時憑空恢復損壞內容。

如果你使用 Btrfs 存重要資料,建議每月跑一次 scrub,配合 SMART、device stats、備份和告警一起使用。真正可靠的資料安全,永遠是校驗、冗餘、監控和備份一起工作,而不是只依賴某一個命令。

參考連結:

记录并分享
使用 Hugo 建立
主題 StackJimmy 設計