跳至內容

Btrfs

出自 Arch Linux 中文维基

譯自 Introduction — BTRFS Documentation

BTRFS 是 Linux 上現代的寫時複製(CoW, Copy-on-Write)文件系統,旨在在提供高級功能的同時,注重容錯能力、修復能力且便於管理。
注意:與其它一些文件系統類似,Btrfs 仍在持續開發中,因此可能存在某些功能尚未成熟以供日常使用。如需確認特定使用場景是否會受到影響,可查閱 Btrfs 官方文檔的狀態章節(英文)及本文的 #已知問題部分。

準備

[編輯 | 編輯原始碼]

安裝用戶空間工具 btrfs-progs,這是執行基本操作所必需的。

若需要從 Btrfs 文件系統啟動(即內核和 initramfs 位於 Btrfs 分區),請檢查引導加載程序是否支持 Btrfs。

創建文件系統

[編輯 | 編輯原始碼]

下文展示如何創建一個新的 Btrfs 文件系統。若要將一個 Ext3/4 分區轉換為 Btrfs,請參考 #從 Ext3/4 轉換。若要使用無分區的配置,請參考 #無分區 Btrfs 磁碟

查閱 mkfs.btrfs(8) 以獲取更多信息。

單設備文件系統

[編輯 | 編輯原始碼]

要在分區 /dev/分區名 上創建一個 Btrfs 文件系統,執行:

# mkfs.btrfs -L 自定义标签 /dev/分区名

Btrfs 文件系統中,元數據的默認節點大小為 16 KiB,而數據的默認扇區大小等於系統頁大小(自動檢測)。如需為元數據指定更大的節點大小(必須是扇區大小的整數倍且為 2 的整數次冪,最大允許 64 KiB),可通過 -n 選項設置節點大小(nodesize),如下例使用 32 KiB 的節點大小:

# mkfs.btrfs -L 自定义标签 -n 32k /dev/分区名
注意:根據 mkfs.btrfs(8) § OPTIONS 手冊頁內容:「較小的節點大小會導致碎片化,但 B 樹變得更高,從而能夠減少鎖競爭。較大的節點大小則能使數據更加緊湊並降低碎片化程度,但在更新元數據塊時內存操作開銷更大。」

多設備文件系統

[編輯 | 編輯原始碼]
警告:

可以為多個設備創建一個 Btrfs 文件系統。Btrfs 支持的 RAID 級別包括 RAID 0、RAID 1、RAID 10、RAID 5 和 RAID 6(詳情參閱下文 profiles)。Btrfs 的 RAID1 profile 僅保存 2 個副本,內核 5.5 版本引入了 RAID1C3 和 RAID1C4,分別對應帶有 3、4 個副本的 RAID 1 級別。可以使用 -d-m 參數分別為數據和元數據配置 RAID 級別。默認情況下,數據只有一份(使用 single),元數據則鏡像存儲(使用 raid1),這相當於一個 JBOD 配置⸺多個磁碟會被看做成一個文件系統,但文件不重複。更多有關如何創建一個 Btrfs RAID 卷的信息請參閱 btrfs wiki: 在多個設備上使用 Btrfs

# mkfs.btrfs -d single -m raid1 /dev/分区1 /dev/分区2 ...

必須在 /etc/mkinitcpio.conf 中加入 udevsystemdbtrfs 鉤子之一才能使用多設備 Btrfs 文件系統。查閱 Mkinitcpio#常用鉤子以獲取更多信息。

創建好文件系統之後,建議使用下面的命令掃描並註冊多設備 Btrfs 文件系統,這樣在掛載多設備文件系統時就僅需指定其中的一個設備:

# btrfs device scan
注意:
  • 可以稍後再將設備添加到多設備文件系統中,詳情請參見 btrfs Wiki 上的這篇文章
  • 多個設備可以大小各異。但如果使用 RAID 配置存儲數據,當一個硬碟的大小比其他的都大時,多出的空間可能不被使用。在 Btrfs 中確定可用空間仍然很困難,可以使用 Btrfs 磁碟使用計算器確定。
  • 有些引導加載程序不支持多設備文件系統,比如 Syslinux
  • Btrfs 不會自動從速度最快的設備讀取,因此混合使用不同類型的磁碟會導致性能表現不穩定。詳情請參閱 Stack Overflow 上的這個回答

#RAID 小節中有關於維護多設備上的 Btrfs 文件系統的一些建議。

Profiles

[編輯 | 編輯原始碼]

Btrfs 使用 profiles 這個概念來表示鏡像、奇偶校驗和條帶屬性,對應 RAID 術語中的「RAID 級別」(若適用)。在同一個 Btrfs 文件系統中,元數據的 profiles(mkfs.btrfs(8)-m 選項)和數據的 profiles(mkfs.btrfs(8)-d 選項)可以不一樣。

一些重要的 profiles:

single
沒有鏡像、條帶和奇偶校驗,讓多個設備映射到單個文件系統中,在 mdadm 術語中被叫做 LINEAR
RAID0
沒有鏡像、條帶和奇偶校驗,但允許並行訪問設備,不像傳統的 mdadm RAID 那樣要求設備大小相同。
RAID1
鏡像,沒有條帶和奇偶校驗,允許從一個設備失效的情況下恢復訪問。

更多 profiles 請參閱手冊 mkfs.btrfs(8) § PROFILES

配置文件系統

[編輯 | 編輯原始碼]

寫時複製(CoW)

[編輯 | 編輯原始碼]

默認情況下 Btrfs 總是對所有文件使用寫時複製(CoW)。寫入操作不會就地覆蓋數據,而是將修改後的數據塊寫入新位置,同時更新元數據指向新位置。請參閱 Btrfs 系統管理指南相關章節以獲取實現細節以及其優缺點。

禁用寫時複製

[編輯 | 編輯原始碼]
警告:在 Btrfs 中禁用寫時複製會禁用數據校驗和 [1] [2],禁用數據校驗和會使 Btrfs 無法得知這些文件是否損壞。與 RAID 1(包括 profile 中的 RAID1RAID1C3RAID1C4)結合使用時,斷電或其他導致損壞的原因可能會造成副本間的數據不同步。

使用 nodatacow 選項掛載子卷可禁用其上新文件的寫時複製特性,注意這只會影響新建的文件,而不會影響已存在的寫時複製文件。nodatacow 參數會禁用壓縮與數據校驗和,參閱 btrfs(5) 以了解細節。

注意:根據 btrfs(5) § MOUNT OPTIONS: 「在單個文件系統中,無法讓某些子卷使用 nodatacow 參數掛載,而其他的使用 datacow 參數掛載。第一個被掛載子卷的掛載參數將會應用於其他所有子卷。」

要禁用空文件或目錄中新文件(同上,不會影響其中已存在的寫時複製文件)的寫時複製特性,請使用下面的命令:

$ chattr +C 目录或文件路径
注意:
提示:為目錄中已存在的所有文件禁用寫時複製可以使用下面的方法:
$ mv /path/to/dir /path/to/dir_old
$ mkdir /path/to/dir
$ chattr +C /path/to/dir
$ cp -a --reflink=never /path/to/dir_old/. /path/to/dir
$ rm -rf /path/to/dir_old
需要保證這個過程中未使用涉及到的數據。關於此處 --reflink=never 參數的使用,詳見下文 #對複製的影響
仍然會觸發寫時複製的情況
[編輯 | 編輯原始碼]

具有 +C 屬性的文件仍然允許有超過一個引用(例如使用 cp reflink 的副本與 Btrfs 中的快照),此時寫時複製依然會生效

本文或本章節的語言、語法或風格需要改進。參考:幫助:風格

原因:子章節嵌套過多。(在en:Talk:Btrfs討論)
對複製的影響
[編輯 | 編輯原始碼]

使用 cp 複製文件時,+C 屬性並非由原文件決定,而相當於在目標路徑新建的文件(從目錄繼承或由子卷是否使用 nodatacow 參數掛載決定),當原文件與目標文件都具有/不具有 +C 屬性時,能夠通過 reflink 進行複製,否則不能。具體運行的結果取決於 --reflink 參數,有以下三種情況:

  • 使用 --reflink=auto 參數(默認情況):若原文件與目標文件都具有/不具有 +C 屬性,則直接 reflink,否則進行深拷貝。
  • 使用 --reflink(或 --reflink=always)參數:若原文件與目標文件都具有/不具有 +C 屬性,則直接 reflink,否則報錯。
  • 使用 --reflink=never 參數:強制進行深拷貝。

總的來說,如果確實要避免寫時複製,必須顯式地使用 --reflink=never 參數(若目標路徑沒有 +C 屬性,先創建一個有 +C 屬性的空文件再覆蓋它)。有關 --reflink 參數的更多信息請參閱 cp(1)

對快照的影響
[編輯 | 編輯原始碼]

如果為禁用了寫時複製的文件創建快照,快照會鎖定原文件塊位置,因此首次寫入該文件的塊時會觸發寫時複製。但文件仍保留 +C 屬性,故後續對同一文件塊的寫入仍為原地操作,直至下次創建快照。

頻繁快照會減弱 +C 屬性的效果,因為在每次快照後的第一次寫入都會觸發寫時複製。要避免這種情況,可以把所有禁用寫時複製的文件放在一個單獨的子卷中並避免為該子卷創建快照。

壓縮

[編輯 | 編輯原始碼]

Btrfs 支持透明自動壓縮,這不僅能縮減文件體積,還能通過減弱寫入放大效應顯著延長快閃記憶體介質的使用壽命,詳見 Fedora:Changes/BtrfsByDefault#Compression[3][4]。在某些情況下(例如單線程繁重文件 I/O 時),壓縮可以提升性能,但在其他場景中(如多線程或高 CPU 占用並涉及大量文件讀寫的任務),性能則會明顯下降。通常採用壓縮算法越快(zstdlzo)性能越好,一些基準測試提供了詳細的性能對比數據。

壓縮類型

[編輯 | 編輯原始碼]

Btrfs 支持的壓縮算法有 zlib(即 zlib 庫提供的 DEFLATE 壓縮算法)、lzo(即 LZO)和 zstd(即 zstd 實現的 Zstandard 壓縮算法)。其中 lzo 無壓縮級別,而 zlibzstd 可調整壓縮級別(zlib:1~9;zstd:-15~-1、1~15,需為整數),級別越高壓縮效果越好而所需時間越長。改變壓縮級別將直接影響 CPU 和 I/O 吞吐,因此,建議在變更前後分別執行基準測試以驗證優化效果。關於壓縮類型的更多信息,可參閱 btrfs(5) § COMPRESSION

警告:如果使用 zstd 算法(尤其是 -15~-1 級別),使用較舊的內核或 btrfs-progs 的系統可能不能讀取或修復您的文件系統。

啟用壓縮

[編輯 | 編輯原始碼]
為文件系統啟用
[編輯 | 編輯原始碼]

掛載時指定 compress=算法[:級別] 掛載選項可自動考慮為文件系統中每個寫入啟用壓縮,其中的 算法 處可以填寫 zliblzozstdno(即不壓縮),可選的 級別 處填寫壓縮級別,不填寫或填寫 0 時取默認值 3(lzo 不適用)。使用該選項時,Btrfs 會檢測文件寫入的數據的首個數據塊經壓縮後體積是否縮小。如果縮小,則壓縮本次寫入的全部內容,否則文件會被標記為 NOCOMPRESS,整個寫入過程及該文件後續的所有寫入過程都不會觸發壓縮 [5]。這是為了防止等待所有待寫入數據完全交付給 Btrfs 並進行嘗試壓縮後,磁碟才開始執行寫入操作。

注意:
  • 壓縮掛載選項會在同一文件系統的所有掛載點(包括不同子卷與綁定掛載)之間共享 [6]
  • 若文件的一次寫入無法壓縮,此後寫入均不會進行壓縮。

這篇文章的某些內容需要擴充。

原因:下文陳述的有關試驗測試的結果缺少引用來源,且此處關於百分比的原文表述並不準確(故譯文不一定正確)。 (在 Talk:Btrfs 中討論)

若改用 compress-force=算法[:級別] 掛載選項,Btrfs 會檢查每次寫入每個數據塊並分別決定是否壓縮。在多個混合用途系統上進行的實證測試表明,使用 compress-force=zstd 相比使用 compress=zstd 能顯著提高空間節省率(從 10% 提升到 20%),但這會導致 CPU 占用率無端(略微)升高且拖長寫入所需時間。官方 Btrfs 指導手冊不推薦使用該選項。

只有在添加以上兩個掛載選項之一後才會自動壓縮新建或修改的文件。

提示:在新的 Btrfs 上安裝 Arch Linux 時,如果需要將其壓縮後存儲,需要在系統安裝前就使用 compress 選項掛載,例如:mount -o compress=zstd /dev/sdxY /mnt/,並注意在其 fstab 中為根目錄文件系統指定相同的 compress 掛載選項。
為現有文件啟用
[編輯 | 編輯原始碼]

要為現有文件啟用壓縮,可使用 btrfs filesystem defragment -c算法 命令,算法 處可選填為 zliblzozstd,但使用此方式指定壓縮級別尚未實現,因此採用默認值 3(lzo 不適用)。例如,執行以下命令可用 zstd 重新壓縮所有文件:

# btrfs filesystem defragment -r -v -czstd /
警告:對具有 CoW 副本(例如快照副本和使用 cp 複製的文件)的文件進行碎片整理會生成兩個不相關的文件,可能大幅增加磁碟使用量。

使用上面的方式壓縮文件不具有持久性,其他寫入操作將應用原有壓縮設置。

以下兩種方式可以持久性啟用對單個文件的壓縮:

$ chattr +c 文件
$ btrfs property set 文件 compression zstd

前一條命令使用的是從 ext2 文件系統繼承的文件屬性舊接口,靈活性不足,只能夠使用默認的 zlib 壓縮算法。後一條命令則可以指定壓縮算法,但指定壓縮級別尚未實現,因此採用默認值 3(lzo 不適用)。

查看壓縮類型和壓縮率

[編輯 | 編輯原始碼]

compsize 接收一個包含文件或目錄(可為整個 Btrfs 文件系統)的列表,輸出其使用的壓縮類型以及實際壓縮率(壓縮後大小/壓縮前大小)。壓縮前大小可能與其他程序(如 du(1))顯示的數值不一致,因為每個 extent 都會被統計且只統計一次⸺即使有多個 reflink,或其部分內容已不再使用但尚未被垃圾回收。

-x 選項可限制在單一文件系統內執行,這在類似於 compsize -x / 的場景中非常有用,可以避免程序因嘗試訪問非 Btrfs 的子目錄而導致整個運行的失敗。

子卷

[編輯 | 編輯原始碼]

「Btrfs 子卷是可獨立掛載的 POSIX 文件樹,而不是也不能看作是塊設備。大多數其他 POSIX 文件系統只有一個可掛載根,而 Btrfs 不僅為整個卷(稱作『頂層子卷』)提供了可掛載根,每個子卷也擁有獨立的可掛載根;一個 Btrfs 卷可以包含不止一個文件樹⸺包含一個『文件森林』。可以將 Btrfs 子卷理解為一個 POSIX 文件命名空間。」[7]

每個 Btrfs 文件系統都有一個 ID 為 5 的頂層子卷。這個子卷不能被移除或被其他子卷替代。頂層子卷在文件系統中的路徑為 /,其他子卷則「嵌套」在頂層子卷之下。子卷(不包括頂層子卷)可以在文件系統中移動,可以嵌套在任意其他子卷下,即其路徑可變,但子卷 ID 不可更改。

掛載文件系統時默認情況下掛載的是頂層子卷(除非更改默認子卷),可以通過選項來掛載指定子卷

子卷的主要用途之一是 #快照

更多詳細信息請參閱以下連結:

創建子卷

[編輯 | 編輯原始碼]

要創建子卷,必須先掛載其上層子卷。

# btrfs subvolume create 子卷父目录/子卷名

例如,在 /mnt 所在子卷下創建子卷 @sub(路徑為 /mnt/@sub):

# btrfs subvolume create /mnt/@sub
注意:
  • 使用 --parents 選項可以自動創建不存在的父目錄。
  • Btrfs 中子卷名可以是任何有效的目錄名,以 @ 符號開頭只是一個常見的命名約定。

列出子卷

[編輯 | 編輯原始碼]

查看路徑所屬文件系統的所有子卷列表:

# btrfs subvolume list -t 路径

-t 選項會觸發更易讀的表格視圖。

刪除子卷

[編輯 | 編輯原始碼]

刪除子卷:

# btrfs subvolume delete 子卷路径

如果子卷包含其他子卷,需要添加 -R/--recursive 選項遞歸刪除包含的所有子卷。子卷也可以當作常規目錄刪除(使用 rm -rrmdir)。

警告:確保在刪除子卷之前未掛載該子卷。刪除已掛載的子卷可能導致文件系統不一致。

掛載子卷

[編輯 | 編輯原始碼]

將需掛載的子卷設置為默認子卷或使用 subvol=子卷路徑(相對於頂層子卷)subvolid=子卷ID 標誌掛載文件系統,可以將子卷像文件系統分區一樣掛載。例如,可以將一個名為 subvol_root 的子卷掛載為 /。通過在頂層子卷下創建各種子卷,然後掛載到適當的掛載點,模擬傳統的文件系統分區。因為子卷 ID 在恢復 #快照時可能會改變,建議使用 subvol 參數掛載子卷。

提示:
  • 子卷 ID 可通過 #列出子卷顯示。
  • 不使用默認做法(將頂層子卷作為 /)可以簡化子卷布局的更改。因此,考慮創建一個子卷掛載為 /
注意:
  • 如果要將子卷掛載為 /,需要在 rootflags 內核參數中指定掛載子卷的選項(一些引導加載程序可以自動添加,例如 GRUBgrub-mkconfig 命令),並編輯 /etc/fstab。或者,可以 #更改默認子卷
  • 譯自 btrfs(5) § MOUNT OPTIONS:「大多數掛載選項應用於整個文件系統,只有第一個掛載的子卷的選項才會生效。這是由於實現缺失,將來可能會改變。這意味著(例如)你無法使用掛載選項為每個子卷單獨設置 nodatacownodatasumcompress。這最終應該會被修復,但事實證明在 Linux VFS 框架內正確實現是困難的。」

有關目前及計劃可以為每個子卷單獨應用的掛載選項,請參閱 Btrfs Wiki FAQ

請參閱 Snapper#建議的文件系統布局Btrfs SysadminGuide#Managing SnapshotsSysadminGuide#Layout,了解使用子卷的示例文件系統布局。

有關 Btrfs 特有的掛載選項的完整列表,請參閱 btrfs(5) § BTRFS SPECIFIC MOUNT OPTIONS

更改默認子卷

[編輯 | 編輯原始碼]

如果沒有提供 subvolsubvolid 選項,將掛載默認子卷。要將子卷設置為所在文件系統的默認子卷,執行:

# btrfs subvolume set-default 子卷路径

或者使用:

# btrfs subvolume set-default 子卷ID 路径

路徑所在文件系統的默認子卷設置為 ID 為子卷ID 的子卷。

提示:子卷 ID 可通過 #列出子卷顯示。

使用 btrfs subvolume set-default 更改默認子卷後,頂層子卷需要使用 subvol=/subvolid=5 掛載選項掛載 [8]

注意:GRUBgrub-mkconfig 腳本遵守 Btrfs 的默認子卷設置⸺如果 / 是頂層子卷,始終不會指定 subvol=/subvolid=5 掛載選項,可能導致無法啟動;如果 / 非頂層子卷,始終會指定相應的 subvol 選項,導致無法僅通過設置默認子卷回退(bug 報告)。目前可以通過手動修改 grub.cfgrootflags 內核參數解決(參見 #掛載子卷),或者使用工具自動在 GRUB 中為快照創建啟動項(參見 #引導進入快照)。另外,如果 grub.cfg 的實際位置發生改變,例如包含 /boot 的子卷改變,需要再次運行 grub-install。詳見這個論壇帖子

配額

[編輯 | 編輯原始碼]
警告:儘管 Btrfs 的 Qgroups(配額組)已被認為在一般用途下是穩定的,但啟用配額,尤其是在頻繁或存在大量快照的設置中,仍可能導致性能下降,特別是在刪除快照時。Qgroup 計帳會引入額外的元數據開銷,在快照操作頻繁的系統中可能影響響應速度。

近年來的內核改進(5.15 及以後版本)已解決許多歷史問題,但在某些高級用例中仍存在一些限制,例如深度嵌套的子卷或複雜的 Qgroup 層級結構。從 2016 年起提出的建議——在啟用配額前應仔細評估你的使用場景——至今仍然適用。請務必查閱最新版的 Btrfs 文檔 以了解當前詳情。

Btrfs中的配額支持是通過使用配額組或 qgroup 在子卷級別實現的:默認情況下,每個子卷都以 0/subvolume_id 的形式分配配額組。 但是,如果需要的話,可以使用任意數字創建配額組。

要使用 Qgroup,你首先需要啟用它:

# btrfs quota enable path

從此時開始,新創建的子卷將由這些配額組控制。 為了能夠為已創建的子卷啟用配額,首先正常啟用配額,然後使用它們的 subvolume_id 為每個子卷創建一個配額組,再重新掃描它們:

# btrfs subvolume list path | cut -d' ' -f2 | xargs -I{} -n1 btrfs qgroup create 0/{} path
# btrfs quota rescan path

Btrfs 中的配額組形成樹層次結構,其中 Qgroup 附加到子卷。大小限制由每個 Qgroup 獨立配置且在並在包含給定子卷的樹中達到任何限制時應用。

配額組的限制可以應用於總數據使用,非共享數據使用,壓縮數據使用或全部。文件複製和文件刪除可能都會影響限制,因為如果刪除原始卷的文件並且只剩下一個副本,則另一個 Qgroup 的非共享限制可能會更改。例如,新快照幾乎與原始子卷共享所有塊,對子卷的新寫入將向專用限制提升,一個卷中的公共數據的刪除將升高到另一個卷中的專用限制。

要對 Qgroup 應用限制,請使用命令 btrfs qgroup limit。根據你的使用情況,使用總限制,非共享限制( -e)或壓縮限制( -c)。

顯示文件系統使用中給定路徑的使用情況和限制:

# btrfs qgroup show -reF path

提交間隔

[編輯 | 編輯原始碼]

將數據寫入文件系統的頻率由 Btrfs 本身和系統的設置決定。Btrfs 默認設置為 30 秒檢查點間隔,新數據將在 30 秒內被提交到文件系統。 這可以通過在 /etc/fstab 增加 commit 掛載參數來修改:

LABEL=arch64 / btrfs defaults,noatime,compress=lzo,commit=120 0 0

系統範圍的設置也會影響提交間隔。它們包括 /proc/sys/vm/* 下的文件,這超出了本文的範圍,因此不再贅述。 它們的內核文檔位於 https://docs.kernel.org/admin-guide/sysctl/vm.html

固態硬碟 TRIM

[編輯 | 編輯原始碼]

Btrfs 文件系統能夠從支持 TRIM 命令的 SSD 驅動器中釋放未使用的塊。可使用掛載參數 discard=async 啟用異步丟棄(asynchronous discard)支持,linux 6.2 版本已經默認啟用該功能。已釋放的空間範圍不會被馬上丟棄,它們會被集中起來並在稍後由一個單獨的工作線程進行 TRIM,這將能改善提交延遲。

異步丟棄可以安全地同定期TRIM使用[9]

有關啟用和使用 TRIM 的更多信息,請參閱固態硬碟#TRIM

使用

[編輯 | 編輯原始碼]

交換文件

[編輯 | 編輯原始碼]
注意:跨設備文件系統上的交換文件不受支持,參見btrfs(5) § SWAPFILE SUPPORT以了解所有限制。

創建交換文件的正確方法是首先創建一個非快照子卷以存儲交換文件,

# btrfs subvolume create /swap 
提示:考慮直接在頂層子卷上創建子卷,例如@swap。然後將子卷掛載/swap(或其他可訪問路徑)。

創建交換文件:

# btrfs filesystem mkswapfile --size 4g --uuid clear /swap/swapfile

如果未指定 --size 選項,交換文件默認大小為2 GiB。

啟用交換文件:

# swapon /swap/swapfile

最後編輯fstab,添加交換文件的配置:

/etc/fstab
/swap/swapfile none swap defaults 0 0

更多信息參見Fstab#用法

注意:也可以手動創建交換文件,通過chattr設置整個子卷的No_COW屬性,然後按照Swap#建立交換文件的內容創建交換文件。參見btrfs(5) § SWAPFILE SUPPORT

要使用休眠功能,除了配置交換文件外,你還需要完成電源管理/掛起與休眠中描述的額外步驟。

顯示已使用的/空閒空間

[編輯 | 編輯原始碼]

df(1) 這樣的用戶空間工具可能不會準確的計算剩餘空間 (因為並沒有分別計算文件和元數據的使用情況) 。推薦使用 btrfs filesystem usage 來查看使用情況。比如說:

# btrfs filesystem usage /
注意:btrfs filesystem usageRAID5/RAID6 設備上可能無法正常工作。

或者使用btrfs filesystem df在非root權限下快速檢查已分配空間的使用情況:

$ btrfs filesystem df /

請參閱 [10] 以獲取更多信息。

du(1)ncdu(1) 這類分析文件系統子集空間使用的工具同樣受到影響,因為其沒有考慮reflink,快照和壓縮。可以考慮使用btduAURcompsize這類可識別btrfs特性的工具。

碎片整理

[編輯 | 編輯原始碼]

Btrfs 支持通過配置掛載參數 autodefrag 來實現在線的碎片整理,參見 btrfs(5) § MOUNT OPTIONS 。要手動整理你的根目錄的話,可以使用:

# btrfs filesystem defragment -r /

使用不帶 -r 開關的上述命令將導致僅整理該目錄的子卷所擁有的元數據。這允許通過簡單地指定路徑進行單個文件碎片整理。

警告:對具有 CoW 副本(快照副本或使用cp或 bcp 創建的文件)進行碎片整理以及使用帶壓縮算法的 -c 開關進行碎片整理可能會導致生成兩個不相關的文件從而大幅增加磁碟使用量。

Btrfs 提供對 RAID 一類的 #多設備文件系統的原生支持。自修復冗餘陣列和在線數據在線平衡是使btrfs RAID 與mdadm區分開來的重要特性。參閱 the Btrfs wiki page 獲得更多信息。Btrfs 管理員手冊提供了一些額外技術背景信息。

警告:奇偶校驗 RAID(RAID 5/6)代碼中存在多個嚴重的數據丟失錯誤。 檢查 Btrfs 文檔的 RAID5/6 頁面 (英文) 和 BUG 匯報 (linux-btrfs 郵件列表 (英文)) 以獲取更多信息。2020 年 6 月, 有人提出了一個 通俗易懂的現存問題列表 (英文) 和一個 有用的恢復指南 (英文)

檢修 (Scrub)

[編輯 | 編輯原始碼]

這篇文章的某些內容需要擴充。

Btrfs Wiki 術語表中寫到,Scrub 是一種"在線文件系統檢查工具"。它能讀取文件系統中的文件和元數據,並使用校驗值和 RAID 存儲上的鏡像區分並修復損壞的數據。

注意:運行 scrub 會阻止系統待機, 詳見 這個討論
手動啟動
[編輯 | 編輯原始碼]

啟動一個(後台運行的)包含 / 目錄的文件系統在線檢查任務:

# btrfs scrub start /

檢查該任務的運行狀態:

# btrfs scrub status /
通過服務或者定時器啟動
[編輯 | 編輯原始碼]

btrfs-progs 軟體包帶有 btrfs-scrub@.timer 系統單元,用來每月運行 scrub 命令。通過添加掛載點的參數來啟用它,例如btrfs-scrub@-.timer (/) 或者 btrfs-scrub@home.timer (/home)。你可以使用systemd-escape -p /path/to/mountpoint來轉義路徑,參見systemd-escape(1)

也可以通過啟動 btrfs-scrub@.service 來手動運行 scrub (使用同樣的轉移後路徑),相較 (以 root 用戶身份運行) btrfs scrub,這麼做的優點是輸出內容會記錄在 Systemd 日誌中。

數據平衡 (Balance)

[編輯 | 編輯原始碼]

"Balance 將會通過分配器再次傳遞文件系統中的所有數據。它主要用於在添加或刪除設備時跨設備重新平衡文件系統中的數據。如果設備出現故障,餘額將為冗餘 RAID 級別重新生成缺失的副本。"[11]。參閱上游的 FAQ.

在單設備文件系統上,數據平衡對於(臨時)減少分配但未使用(元)數據塊的數量也是有用的。有時候這對於解決 "filesystem full" 故障來說也是必須的。

# btrfs balance start --bg /
# btrfs balance status /

快照

[編輯 | 編輯原始碼]

"快照是和其它子卷共享數據和元數據的簡單子卷, 利用了 btrfs 的寫時複製特性。" 詳見 Btrfs Wiki SysadminGuide#Snapshots

要創建一個快照:

# btrfs subvolume snapshot source [dest/]name

source為要創建快照的對象,[dest/]name為快照安放路徑。

加入 -r 參數可以創建一個只讀快照. 為只讀快照創建一個快照可以獲得一個只讀快照的可寫入版本.

注意:
  • 將一個只讀快照通過btrfs property set -f -ts '/path/to/snapshot' ro false原位轉換為可寫快照是可能的。但並不推薦這樣做,因為之後任何增量發送/接受(send/receive)操作會造成問題。創建一個新的可寫快照可以預防這類問題。
  • 快照不是遞歸包含的,這意味著子卷內的子卷在快照裡是空目錄。

發送和接收

[編輯 | 編輯原始碼]

可以通過 send 命令發送一個快照,通常會與 btrfs 中的 receive 組成管道.例如將快照 /root_backup (也許是/的備份) 發送到 /backup:

 # btrfs send /root_backup | btrfs receive /backup

只能發送只讀快照,上面的命令在將子卷複製到外部設備 (例如備份驅動器) 時會很有用。

接受結束後將創建對應子卷,無需手動再創建。

還有一個例子創建了/mnt/arch-v2/subvolumes/@var子卷:

# btrfs send --proto 2 --compressed-data '/mnt/arch/snapshots/@var' | btrfs receive '/mnt/arch-v2/subvolumes/'

參數--proto 2--compressed-data在本例中能夠更有效地發送快照(假設數據可壓縮)。

也可以只發送兩個快照間發生變化的部分,例如如果你已經發送了快照 root_backup ,然後又建立了一個新的只讀快照 root_backup_new ,可以這樣完成增量發送:

 # btrfs send -p /root_backup /root_backup_new | btrfs receive /backup

現在你 /backup 的快照會是 root_backup_new

參閱 Btrfs Wiki 上關於增量備份的頁面 (英文) 獲得更多信息 (例如使用工具自動化這一過程)。

去重

[編輯 | 編輯原始碼]

使用寫時複製,Btrfs 能夠複製文件或整個子卷而無需實際複製數據。但是,無論何時更改文件,都會創建一個新的「真正的」副本。重複數據刪除更進一步,通過主動識別含有相同內容的數據塊並將它們通過 CoW 合併到同一個區(extend)內。

專用於 Btrfs 分區去重的工具包括 duperemovebees。也許你還希望基於文件的級別對數據進行重複數據刪除,比如 rmlint-gitrdfindjdupesAUR 或者 dduper-gitAUR。有關這些程序的可用功能的概述和其他信息,請參閱上游 Wiki 條目 (英文)

調整大小

[編輯 | 編輯原始碼]
警告:為避免數據丟失,確保在調整大小前備份好你的數據。

你可以增加文件系統的大小到設備的最大可用空間,或到一個指定大小。確保你在嘗試增加文件系統大小前設備或邏輯卷有足夠空間。 當指定一個設備上的文件系統到指定大小時,不論增加或減少,確保新的大小滿足下面的條件:

  • 新的大小必須大於已有數據的大小,否則會導致數據損失。
  • 新的大小必須等於或小於當前設備的可用空間。
注意:如果你還計劃減小文件系統所在的邏輯卷大小,請先減小文件系統大小後再嘗試減小邏輯卷的大小。

將文件系統擴展到設備的最大可用大小:

# btrfs filesystem resize max /

將文件系統擴展到特定大小:

# btrfs filesystem resize size /

size 替換為你需要的大小(按字節計算)。也可以為大小指定單位,如K(千字節),M(兆字節)或G(吉字節)。 或者也可以通過在大小前添加前綴指定增加(+)或減少(-)的變化量:

# btrfs filesystem resize +size /
# btrfs filesystem resize -size /

已知問題

[編輯 | 編輯原始碼]

一些在嘗試之前應該知道的限制。

加密

[編輯 | 編輯原始碼]

Btrfs 暫未內置加密支持,但當前正進行一項基於 Fscrypt英語Fscrypt 的加密集成工作 [12]

不過用戶仍可在運行 mkfs.btrfs 前加密分區,具體參見 dm-crypt/加密整個系統。另一種方案是採用棧式文件系統加密

檢查 btrfs 文件系統問題

[編輯 | 編輯原始碼]

btrfs check 工具目前有一些已知問題,在繼續深入閱讀了解之前,您不應該直接運行它, 參見 #檢查 Btrfs 文件系統小節。

提示和技巧

[編輯 | 編輯原始碼]

無分區 Btrfs 磁碟

[編輯 | 編輯原始碼]
警告:這種配置不建議用於啟動設備,推薦設置一個單獨的EFI 系統分區和Btrfs分區。 此外,GRUB 強烈反對安裝GRUB到無分區磁碟。

Btrfs 能占用整個存儲設備,使用子卷模擬分區表來替代 MBRGPT 分區表。雖然無分區磁碟不需要使用其它方法創建分區,然後在一個分區上創建 Btrfs 文件系統,但在單個磁碟上使用無分區配置存在一些限制:

  • 不能在同一磁碟上的不同分區上創建其它的文件系統
  • 受上一條影響,無法在該磁碟上創建EFI 系統分區。需要額外的儲存設備用於 UEFI 啟動。

運行下面的命令把整個設備的分區表替換成 Btrfs:

# mkfs.btrfs /dev/sdX

如果設備上存在分區表,則需要使用:

# mkfs.btrfs -f /dev/sdX

例如, 指定/dev/sda 而不是 /dev/sda1。後一種形式會格式化現有的分區而不是替換掉原有的分區表。由於根分區是 Btrfs 文件系統,請確保已將 btrfs 編譯進內核, 或者將 btrfs 放入 Mkinitcpio#模塊(MODULES)中並且重新生成 initramfs

像使用普通的 MBR 分區表存儲設備一樣安裝引導加載程序, 參考 Syslinux#手動安裝GRUB/技巧和竅門#安裝到分區上或者無分區磁碟上。 如果你的內核因為 Failed to mount /sysroot. 錯誤無法啟動, 請在 /etc/default/grub 裡添加 GRUB_PRELOAD_MODULES="btrfs" 並重新生成 GRUB 配置文件 。

從 Ext3/4 轉換

[編輯 | 編輯原始碼]
警告:Btrfs 的郵件列表中報告了多起轉換不完整/損壞/失敗的案例。在開始之前請確定您有可用的備份並且願意承擔丟失數據的風險。 參見Btrfs維基的Convert頁。

從安裝 CD 啟動,然後轉化分區:

# btrfs-convert /dev/partition

掛載轉換後的分區並修改 /etc/fstab 文件,指定分區類型 (type 為 btrfs,並且 fs_passno[最後一列] 要修改為0,因為 Btrfs 在啟動時並不進行磁碟檢查)。 還要注意的是分區的 UUID 將有改變,所以使用 UUID (指定分區) 時,請更新 fstab 中相應的條目。 chroot 到系統並重建你的引導加載程序(如果對此過程不熟悉,參考從現有 Linux 發行版安裝 Arch Linux )。 如果轉換了根文件系統,還需要在 chroot 環境中重建初始化內存檔以確保系統正確啟動。

注意:
  • 如果轉換過程中有任何異樣,不管是無法掛載新轉換的 Btrfs 文件系統或是無法往其中寫入數據,只要備份子卷 /ext2_saved 還在,就可以進行回滾。請使用 btrfs-convert -r /dev/partition 命令進行回滾,這將會丟棄任何對新轉換 Btrfs 文件系統的更改。
  • 如果掛載已轉換的 ext 分區時出現如下錯誤:ERROR: dev extent devid 1 physical offset XXX len XXX is beyond device boundary XXX,那麼在分區末尾預留一些空閒空間後,轉換可能會成功。請先回滾轉換,然後使用 resize2fs 將分區縮小 50000 個塊,再擴大 5000 個塊(從而創建出 45000 個空閒塊)。然後再次嘗試轉換。參見 上游 bug 報告

確認沒有問題後,通過刪除 ext2_saved 備份子卷完成轉換的最後一步。請注意,如果沒了它 (備份子卷),你將沒辦法還原回 ext3/4 文件系統。

# btrfs subvolume delete /ext2_saved

最後通過數據平衡回收空間。

別忘了先前安裝的一些應用需要額外設置來適配Btrfs。

注意:Ext3/4 轉換到 Btrfs 的過程很耗時。一個普通機械硬碟上的4TB文件系統轉換耗時可高達10小時。

損壞恢復

[編輯 | 編輯原始碼]
警告:btrfs check 工具有一些已知問題,參見 #檢查 Btrfs 文件系統 小節。

btrfs-check 不能在一個已掛載的文件系統上工作。為了能夠在不從 Live USB 啟動的情況下使用 btrfs-check,需要將其添加到初始內存檔:

/etc/mkinitcpio.conf
BINARIES=(btrfs)

然後重新生成 initramfs

之後如果啟動時出現問題,則可以使用該實用程序進行修復。

注意:如果 fsck 進程必須使空間緩存 (和/或其他緩存?) 無效 (invalidate cache),那麼隨後的引導會掛起一段時間,這是正常的(進程可能會給出關於 btrfs-transaction 掛起的控制台消息)。系統應該在一段時間後從中恢復正常。

查閱 btrfs-check(8) 以獲取更多信息。

引導進入快照

[編輯 | 編輯原始碼]

要引導進入快照,因為快照可以像子卷那樣被掛載,所以請像掛載子卷為根分區那樣進行同樣的流程 (已交代於#掛載子卷為根掛載點的一段中)。

  • 如果使用 GRUB,則可以在 grub-btrfsgrub-btrfs-gitAUR 的幫助下,在重新生成配置文件時使用 Btrfs 快照自動填充啟動菜單。
  • 如果使用 rEFInd,則可以在 refind-btrfsAUR 的幫助下,啟用 refind-btrfs.service後,在重新生成配置文件時使用 Btrfs 快照自動填充啟動菜單。

搭配 systemd-nspawn 使用 Btrfs 子卷

[編輯 | 編輯原始碼]

可查閱 Systemd-nspawn#使用Btrfs子卷作為容器的根Systemd-nspawn#在 systemd-nspawn 中運行 docker 等文章。

減少訪問時間元數據的更新

[編輯 | 編輯原始碼]

由於Btrfs的寫時複製性質,訪問文件就能夠觸發元數據的寫時複製。減少訪問時間的更新頻率可能會消除這種不希望的硬碟使用並提高性能。參見Fstab#atime 參數

增量備份到外置設備

[編輯 | 編輯原始碼]

下列包利用 btrfs sendbtrfs receive 將備份增量發送到外置設備上。 參考它們的文檔來查看實現,功能和需求的不同。

  • btrbk — Btrfs子卷的快照和遠程備份工具
https://github.com/digint/btrbk || btrbk
  • snap-sync — 使用Snapper快照並備份到外置設備或遠程機器
https://github.com/wesbarnett/snap-sync || snap-sync

下列工具運行備份snapper快照到非Btrfs文件系統。

  • snapborg — 一個類似borgmatic的工具,將snapper快照與borg整合起來
https://github.com/enzingerm/snapborg || snapborgAUR

自動快照

[編輯 | 編輯原始碼]

要管理並自動創建快照,你可以使用像SnapperTimeshiftYabsnap這樣的快照管理器。

自動通知

[編輯 | 編輯原始碼]

桌面通知能幫助您及時察覺嚴重的 Btrfs 問題,相較於完全不提供通知,能提供更好的問題感知。

btrfs-desktop-notificationAUR 為以下事件提供桌面通知:

  • 啟動進入任何只讀快照或系統時
  • dmesg 日誌中出現 Btrfs 警告、錯誤或致命消息

更多信息及配置方法,請參見 https://gitlab.com/Zesko/btrfs-desktop-notification

疑難解答

[編輯 | 編輯原始碼]

請查閱 Btrfs 疑難解答Btrfs 常見問答集(英文)以獲得排除一般問題的信息。

分區偏移

[編輯 | 編輯原始碼]
注意:當您試圖將 core.img 嵌入到已分區磁碟上時,可能會發生偏移問題。這意味著可以將 GRUB 的 corg.img 直接嵌入到無分區磁碟 (例如 /dev/sdX) 上的 Btrfs 存儲池中。

GRUB 可以引導啟動 Btrfs 分區,但是因為模塊可能會比其它文件系統大,grub-install 生成的 core.img 文件超過了 MBR 與第一個分區之間的空間大小 (63 扇區/31.5KiB)。最新版的 fdiskgdisk 等磁碟工具會通過第一個分區前空出 1-2MiB 的空間來避免此問題。

根丟失

[編輯 | 編輯原始碼]

本文或本章節的事實準確性存在爭議。

原因: Suggests editing a non-configuration file manually.(在 Talk:Btrfs#Should not suggest to edit files in /usr/share 中討論)


當從一個RAID配置的系統中啟動用戶可能會遇到錯誤:error no such device: root。編輯/usr/share/grub/grub-mkconfig_lib,移除行echo " search --no-floppy --fs-uuid --set=root ${hints} ${fs_uuid}"中的兩個引號。重新生成grub的配置文件,後系統應該能夠正常啟動。

警告:不建議覆蓋軟體包提供的文件,因其會在下次更新時被覆蓋。

掛載超時

[編輯 | 編輯原始碼]

有時(尤其在大型 RAID1 陣列上)系統啟動時會出現掛載超時的現象,並帶有如下日誌信息:

Jan 25 18:05:12 host systemd[1]: storage.mount: Mounting timed out. Terminating.
Jan 25 18:05:46 host systemd[1]: storage.mount: Mount process exited, code=killed, status=15/TERM
Jan 25 18:05:46 host systemd[1]: storage.mount: Failed with result 'timeout'.
Jan 25 18:05:46 host systemd[1]: Failed to mount /data.
Jan 25 18:05:46 host systemd[1]: Startup finished in 32.943s (firmware) + 3.097s (loader) + 7.247s (kernel)>
Jan 25 18:05:46 host kernel: BTRFS error (device sda): open_ctree failed

這可以通過 fstab 中特定的 systemd 掛載選項 x-systemd.mount-timeout 提供系統以更長的超時時間來輕鬆解決。例如:

 UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx  /data  btrfs  rw,relatime,x-systemd.mount-timeout=5min  0 0

出現 BTRFS: open_ctree failed 錯誤

[編輯 | 編輯原始碼]

本文或本章節的事實準確性存在爭議。

原因: 內容過時。自從systemd和udev都使用systemd-udevd後,用systemd替換udev鉤子沒有任何意義。(在 Talk:Btrfs 中討論)


截至 2014 年 11 月,一個似乎存在於 systemdmkinitcpio 中的 Bug 可能會導致在 mkinitcpio.conf 中使用 btrfs 鉤子(hook)的用戶在啟動多設備文件系統的 Btrfs 卷時遇到以下錯誤:

BTRFS: open_ctree failed
mount: wrong fs type, bad option, bad superblock on /dev/sdb2, missing codepage or helper program, or other error

In some cases useful info is found in syslog - try dmesg|tail or so.

You are now being dropped into an emergency shell.

一種解決辦法是,在/etc/mkinitcpio.conf中,將 HOOKS 中的 btrfs 移入 MODULES 中,然後重新生成 initramfs 並重新啟動。

另外,如果在掛載 RAID 卷組缺少某個卷時,也有可能會發生這個錯誤。這種情況下,需要把 degraded 加入到 /etc/fstab 中;如果根目錄在卷組上,需要同時加入內核參數 rootflags=degraded

接上文,截至 2016 年 8 月,針對這一問題,一個可能的解決方案是在 /etc/fstab 中僅靠單個硬碟來掛載陣列,然後讓 Btrfs 自動發現並追加其它硬碟。UUID 和 LABEL 等基於組的標識符似乎是導致出現錯誤的原因。比如說,由「disk1」(磁碟 1) 和「disk2」(磁碟 2)組成的雙設備 RAID1 陣列會被分配到一個 UUID。但是請在 /etc/fstab 中只使用 /dev/mapper/disk1 來指定磁碟陣列,而不要使用 UUID。更多解釋,參見這個博客文章

另一個可能的解決方法是在 mkinitcpio.conf 中移除 udev 鉤子並替換為 systemd 鉤子。此時 btrfs 不應出現在 HOOKSMODULES 列表中。

請查閱原論壇討論FS#42884 獲得更多的討論內容和信息。

檢查 Btrfs 文件系統

[編輯 | 編輯原始碼]

本文或本節內容已經過時。

原因: "大開發階段"狀態已經過時。 (在Talk:Btrfs討論)
警告:Btrfs(特別是 btrfs check 命令工具)仍處在大開發階段,強烈建議在加上 --repair 參數運行 btrfs check 前先做一個備份,並提前查閱 btrfs-check(8)

btrfs-check(8) 可以檢查並修復一個未掛載的 Btrfs 文件系統。但是由於它尚未開發完成,它並不能修復某些錯誤(即使這些錯誤沒有導致文件系統無法掛載)。

持續的硬碟活動

[編輯 | 編輯原始碼]

內核版本6.2開始, mount(8) 默認啟用 discard=async 選項。 這個設置被報告會造成硬碟的持續活動(甚至是待機狀態下),因為丟棄隊列填充的速度快於其處理速度。這會造成電源使用增加,特別是NVMe設備。

到了內核版本6.3後,問題的解決辦法是將iops_limit默認值從100改為1000。在舊版內核上,你可以手動設置到一個需要的值,例如:

# echo 1000 > /sys/fs/btrfs/uuid/discard/iops_limit

其中uuid是btrfs文件系統的UUID。限制值1000需要通過實驗進行調整。

要在啟動時設置該參數,可能要用到Systemd#systemd-tmpfiles - 臨時文件,例如創建下列文件:

/etc/tmpfiles.d/btrfs-discard.conf
w /sys/fs/btrfs/uuid/discard/iops_limit - - - - 1000

或者在fstab中使用nodiscard掛載選項禁用異步丟棄功能,使用定期TRIM來替代。

Device total_bytes should be at most X but found Y

[編輯 | 編輯原始碼]

若驅動器從其他計算機遷移或設備順序變更,且報告的大小差異極小(至多幾MB),可能是啟用了 HPA(主機保護區域)

可使用 hdparm 驗證 HPA 是否啟用:

# hdparm -N 设备

輸出將顯示兩個數值:可見扇區數與實際扇區數。若兩者不同則表明HPA已啟用。

若主板強制設置此功能且固件未提供關閉選項,唯一解決方案是收縮受影響文件系統。此操作最易在原始計算機或未應用HPA的機器上執行。

設備空間不足

[編輯 | 編輯原始碼]

博客文章《解決Btrfs文件系統空間不足問題》建議並解釋了以下檢查步驟:

  1. 立即清理空間(刪除歷史快照)
  2. 文件系統是否真滿?元數據和/或數據塊分布不均(運行 btrfs balance
  3. 文件系統是否真滿?數據塊分布不均
  4. 文件系統是否真滿?元數據分布不均
  5. 因空間不足無法執行平衡操作(運行 btrfs balance 前,先用 btrfs device add 臨時添加設備如U盤或環回設備)

另可參閱 btrfs 元數據滿了怎麼辦 - 依雲's Blog

有關 ENOSPC(「磁碟空間不足」)的最新處理指南,請參閱 ENOSPC - No available disk space | Forza's Ramblings

另請參閱

[編輯 | 編輯原始碼]