Btrfs（Btree 檔案系統，通常念成 Butter FS，Better FS 或 Btree FS），一種支援寫入時複製（COW）的檔案系統，執行在 Linux 作業系統，採用 GPL 授權。Oracle 於 2007 年對外宣佈這項計劃，並釋出原始碼，在 2014 年 8 月釋出穩定版。目標是取代當時在 Linux 上廣泛使用的 ext3 檔案系統，改善檔案系統的限制，增加單個檔案大小上限支援，總檔案系統大小支援以及檔案檢查支援。Btrfs 還加入了可寫快照（writable snapshots）、快照的快照（snapshots of snapshots）、內建磁碟陣列（RAID），以及子卷（subvolumes）等高階檔案系統功能。在宣傳上，Btrfs 的特點是 容錯、修復及易於管理。 歷史 Btrfs 的核心資料結構 寫時複製 B 樹 最初是由 IBM 研究員 Ohad Rodeh 在 2007 年 USENIX 會議上提出的。Chris Mason 當時是 SUSE 公司的 ReiserFS 工程師，後來加入了 Oracle，並開始開發一種基於 B 樹的新檔案系統。 2008 年，ext3 和 ext4 檔案系統的主要開發者曹子德表示，雖然 ext4 有改進的功能，但它不是一個重大的進步；它使用了舊技術，是一個權宜之計。曹子德說，Btrfs 是一個更好的方向，因為 它在可擴充套件性、可靠性和易管理性方面提供了改進。Btrfs 也有 一些與 reiser34 相同的設計思想。 Btrfs 10 版本具有最終確定的磁碟格式，於 2008 年底釋出，並於 2009 年被接受進入 Linux 核心主線。幾個 Linux 發行版開始在安裝過程中提供 Btrfs 作為根檔案系統的實驗性選擇。 2011 年 7 月，Btrfs 自動碎片整理和擦除功能被合併到 Linux 核心主線的 30 版本中。除了 Oracle 的 Mason 外，富士通的 Miao Xie 也貢獻了效能改進。2012 年 6 月，Chris Mason 離開 Oracle 加入 Fusionio，一年後又與 Josef Bacik 一起加入 Facebook。在這兩家公司工作期間，Mason 繼續他對 Btrfs 的工作。 2012 年，兩個 Linux 發行版將 Btrfs 從實驗性狀態轉變為生產或支援狀態：3 月份的 Oracle Linux ，8 月份的 SUSE Linux Enterprise 。 2015 年，Btrfs 被採用為 SUSE Linux Enterprise Server（SLE）12 的預設檔案系統。 2017 年 8 月，紅帽公司在 Red Hat Enterprise Linux（RHEL）74 的釋出說明中宣佈，不再計劃將 Btrfs 轉變為一個完全支援的功能（它自 RHEL 6 beta 以來一直作為 技術預覽 包含在內），並指出它將在 RHEL 7 釋出系列中保持可用。2019 年 5 月，Btrfs 從 RHEL 8 中移除。RHEL 從 RHEL 6 中的 ext4 轉移到 RHEL 7 中的 XFS。 2020 年，Btrfs 被選為 Fedora 33 桌面變體的預設檔案系統。 特性 特性列表 已實現 聯機碎片整理 聯機卷生長和收縮 聯機塊裝置增加和刪除 聯機負載均衡（塊裝置間的物件移動以達到平衡） 檔案系統級的映象（類 RAID1）、條帶（類 RAID0） 子卷（一個或多個單獨可掛載基於每個物流分割槽） 透明壓縮（目前支援 zlib、LZO 和 ZSTD 從 414 開始支援） 快照（只讀和可寫，寫複製，子卷複製） 檔案克隆 資料和元資料的校驗和（目前是 CRC32C） 就地轉換（帶回滾）ext34 與 ReiserFS 只讀儲存的聯合掛載，稱為檔案系統播種（只讀儲存用作可寫 Btrfs 的寫時複製支援） 使用者定義的事務 塊丟棄支援 傳送 接收（將快照之間的差異儲存為二進位制流） 帶外資料去重（需要使用者空間工具） 能夠處理交換檔案和交換分割槽 已實現但不建議在生產環境中使用 分層的每個子卷配額 RAID 5，RAID 6 計劃但尚未實現 帶內資料去重 線上檔案系統檢查 最多六個奇偶校驗裝置的 RAID，超越了 RAID 5 和 RAID 6 的可靠性 物件級 RAID 0，RAID 1 和 RAID 10 透明加密 持久讀寫快取（ L2ARC ZIL，lvmcache 等） 克隆 Btrfs 提供了一個克隆操作，可以原子地建立一個檔案的寫時複製快照。這樣的克隆檔案有時被稱為 reflinks，因為它們與擬議的相關 Linux 核心系統呼叫有關。 在克隆時，檔案系統不會建立一個指向現有 inode 的新連結；相反，它會建立一個新的 inode，最初與原始檔案共享相同的磁碟塊。因此，克隆只能在同一個 Btrfs 檔案系統的邊界內工作，但是在某些情況下，自 Linux 核心 36 版本起，它可能會跨越子卷的邊界。實際的資料塊不會被複制；同時，由於 Btrfs 的寫時複製（CoW）特性，對任何克隆檔案的修改都不會在原始檔案中可見，反之亦然。 克隆不應與硬連結混淆，硬連結是將多個檔名與單個檔案關聯的目錄項。雖然硬連結可以被認為是同一檔案的不同名稱，但 Btrfs 中的克隆提供了最初共享所有磁碟塊的獨立檔案。 GNU coreutils 自 75 版本支援了這個 Btrfs 特性，透過 cp 命令的 reflink 選項可以使用克隆功能。 除了資料克隆（ FICLONE ），Btrfs 還支援透過 FIDEDUPERANGE 進行帶外去重。這個功能允許兩個具有（甚至部分）相同資料的檔案共享儲存空間。 子卷和快照 Btrfs 子卷可視為一個單獨的 POSIX 檔案名稱空間，向 mount 命令傳遞 subvol 或 subvolid 選項能夠單獨掛載相對應的子卷。其他子卷也可以透過掛載頂層子捲來訪問，此時其他子卷作為頂層子卷的子目錄供使用者訪問。 子卷可以在檔案系統層次結構中的任何位置建立，也可以巢狀。巢狀的子卷在其父子卷中顯示為子目錄，類似於頂層子卷將其他子卷顯示為子目錄的方式。刪除一個子卷前，需要確保該子卷內不存在巢狀的子卷；因此，不能刪除頂層子卷。 Btrfs 檔案系統有一個預設子卷，最初設定為頂層子卷，在傳遞子卷選擇選項時預設掛載。預設子卷可以根據需要更改。 Btrfs 快照是一個與其他子卷共享資料（和元資料）的子卷，使用 Btrfs 的寫時複製實現，對快照的修改在原始子卷中不可見。可寫的快照可以視為原始檔案系統的一個副本。例如，要回滾到一個快照，可以解除安裝修改過的原始子卷，並將快照掛載到它的位置來實現。此時，也可以刪除原始子卷。 Btrfs 的寫時複製（CoW）特性意味著快照可以快速建立，同時剛剛建立時僅消耗很少的磁碟空間。由於快照是一個子卷，因此也可以建立巢狀的快照。對一個子捲進行快照不是一個遞迴的過程；因此，如果建立了一個子卷的快照，該子捲包含的每個巢狀子卷都會對映到同名的空目錄中。 不能對一個目錄進行快照，只有子卷才能有快照。然而，有一種涉及跨越子卷的 reflinks 的解決方案：建立一個新的子卷，包含指向目標目錄內容的跨越子卷的 reflinks。有了這個，就可以建立這個新卷的快照。 Btrfs 中的子卷與傳統的 LVM 邏輯卷非常不同。在 LVM 中，邏輯卷是一個單獨的塊裝置，而 Btrfs 子卷更類似於 POSIX 名稱空間。原始或副本中的任何一個在同一臺計算機上掛載時，對 btrfs 進行 dd 或 LVM 快照會導致資料丟失。 zh 子捲髮送與接收；zhhans 子捲髮送與接收；zhtw 子卷傳送與接收； 給定任意一對子卷（或快照），Btrfs 可以在它們之間生成二進位制差異（透過使用 btrfs send 命令），稍後可以重放（透過使用 btrfs receive），可以接收到另一個 Btrfs 檔案系統上。傳送 接收功能實際上建立（並應用）了將一個子卷轉換為另一個子卷所需的一組資料修改。 傳送 接收功能可以與定期安排的快照一起使用，用於實現檔案系統複製的簡單形式，或用於執行增量備份。 配額組 配額組可以對一個子卷或快照可能消耗的空間設定上限。新的快照最初不消耗配額，因為它的資料與其父卷共享，但之後會因為新檔案和對現有檔案的寫時複製操作而產生空間上的開銷。當配額功能啟用時，每個新的子卷或快照都會自動建立一個配額組。這些初始的配額組是可以分組（使用 btrfs qgroup 命令）成層次結構來實現配額池的構建塊。 配額組只適用於子卷和快照，而不能對單個子目錄、使用者或使用者組強制執行配額。然而，可以透過使用不同的子捲來實現所有需要強制執行配額的使用者或使用者組。 原地轉換 ext234 和 ReiserFS 由於在固定位置的元資料非常少，Btrfs 可以適應後端儲存裝置的各種的空間佈局。btrfsconvert 工具可以透過在其未分配空間中巢狀等效的 Btrfs 元資料 同時保留原始檔案系統的未修改副本，即原地轉換一個 ext234 或 ReiserFS 檔案系統。 轉換需要建立整個 ext234 元資料的副本，而 Btrfs 檔案只是指向與 ext234 檔案使用的相同的塊。這使得在不可逆轉換之前，兩個檔案系統共享大部分塊。由於 Btrfs 的寫時複製特性，在所有檔案修改過程中，原始版本的檔案資料塊都保持不變。在不可逆轉換之前，只有在 ext234 中標記為空閒的塊才用於儲存新的 Btrfs 修改，這意味著轉換可以隨時撤銷轉換（但撤銷轉換會擦除在轉換為 Btrfs 後所做的任何更改）。 所有轉換後的檔案都在 Btrfs 的預設子卷中。轉換工具會在一個單獨的子卷中建立包含對原始 ext234 檔案系統所有引用的稀疏檔案；這一檔案可以作為一個只讀磁碟映像單獨掛載，允許同時訪問原始檔案系統和轉換後的檔案系統。刪除這個稀疏檔案會釋放原有檔案系統額外佔用的空間，並使轉換變得不可逆。 在主線 Linux 核心的 4x 版本中，就地 ext34 缺乏使用與測試，不能保證穩定性。然而，該功能在 2016 年的 btrfsprogs 46 從頭重寫。Btrfs 的就地檔案系統轉換功能自此宣佈穩定。 就地從 ReiserFS 轉換在 2017 年 9 月引入到 Linux 413 核心中。 聯合掛載 種子裝置 在建立一個新的 Btrfs 時，可以使用一個已存在的 Btrfs 作為一個只讀的 種子 檔案系統。新的檔案系統將作為種子上的一個寫時複製覆蓋層，作為一種聯合掛載的形式。種子可以稍後從 Btrfs 中分離，在此之前，重平衡器將簡單地複製任何仍然被新檔案系統引用的種子資料，然後分離。Btrfs 的主要貢獻者 Mason 認為這可能對 Live CD 安裝程式有用，它可以從光碟上的一個只讀 Btrfs 種子啟動，在使用者繼續工作的同時，在後臺將自己重平衡到安裝磁碟上的目標分割槽，然後彈出光碟以完成安裝而不需要重新啟動。 加密 在 2009 年的採訪中，Chris Mason 表示計劃為 Btrfs 增加加密支援。目前，將加密與 Btrfs 結合使用的一種解決方案是使用諸如 dmcrypt LUKS 之類的全盤加密機制在底層裝置上，並在該層之上建立 Btrfs 檔案系統。 開發人員正在努力新增類似 HMAC（SHA256）的鍵控雜湊。 檢查和恢復 Unix 系統傳統上使用 fsck 程式來檢查和修復檔案系統。這個功能是透過 btrfs check 程式實現的。從 40 版本開始，這個功能被認為是相對穩定的。然而，截至 2023 年 6 月，btrfs 文件建議只有在 開發者或經驗豐富的使用者 建議時才使用其repair 選項。截至 2023 年 6 月，SLE 文件建議使用一個 Live CD，執行一個備份，並只在最後的手段時使用修復選項。 還有另一個工具 btrfsrestore，可以用於從一個不可掛載的檔案系統中恢復檔案，而不修改損壞的檔案系統本身。 在正常使用中，Btrfs 基本上是自我修復的，並且可以在掛載時從損壞的根樹結構中恢復，這是因為預設每 30 秒向永久儲存重新整理資料。因此，孤立的錯誤會導致下一次掛載時最多 30 秒的檔案系統更改丟失。這個週期可以透過在 commit 掛載選項中指定所需的值來更改。（以秒為單位） 設計 Ohad Rodeh 在 2007 年的 USENIX 提出的原始方案指出，廣泛用作資料庫的磁碟資料結構的 B 樹不能有效地實現基於寫時複製的快照，因為它的葉子節點是連線在一起的：如果一個葉子被寫時複製，它的兄弟節點和父節點也必須如此，以及它們遞迴的兄弟和父節點，直到整個樹被複制。他建議使用一個修改過的 B 樹（沒有葉子連結），並且每個樹節點都有一個引用計數，但是儲存在一個專門的自由對映結構中，並且對樹的平衡演算法進行了一定的放鬆，使它們對寫時複製友好。結果將是一個適合高效能物件儲存的資料結構，可以執行寫時複製快照，同時保持良好的併發性。 Also 同年，在 Oracle 工作的 Chris Mason 開始了一個能夠使用這種資料結構的快照能力檔案系統的工作，幾乎完全採用這種資料結構 不僅用於元資料和檔案資料，而且遞迴地用於跟蹤樹本身的空間分配。這允許所有遍歷和修改都透過同一份程式碼，只需要實現一次諸如寫時複製、校驗和和映象等特性，就可以在整個檔案系統的各個地方使用。 Btrfs 包含樹組成的幾層結構，所有樹都使用相同的 B 樹實現。樹儲存了按照 136 位鍵排序的通用項。鍵中最高的 64 位是一個唯一的 物件 id。中間 8 位是一個項型別欄位，用於硬編碼到程式碼中作為樹查詢中的項過濾器。物件 可以有多個型別的多個項。剩下的 64 位以型別特定的方式使用。因此，同一物件的項會在樹中彼此相鄰，按型別分組。透過選擇某些鍵值，物件可以進一步按照型別排列。 內部樹節點只是鍵 指標對的平面列表，其中指標是子節點的邏輯塊號。葉節點包含打包到節點前面的項鍵和打包到節點末尾的項資料，在葉填充時兩者向彼此增長。 檔案系統樹 在每個目錄中，目錄條目以 目錄項 的形式出現，它們的鍵值的最低位是它們檔名的 CRC32C 雜湊。它們的資料是一個 位置鍵，或者是它指向的 inode 項的鍵。目錄項一起可以作為路徑到 inode 查詢的索引，但不用於迭代，因為它們按照它們的雜湊排序，有效地隨機排列它們。這意味著在一個大目錄中迭代和開啟檔案的使用者應用程式將產生更多的磁碟尋道，因此在非相鄰檔案之間尋道 這是其他檔案系統中具有雜湊排序目錄的顯著效能損耗，例如 ReiserFS， ext3（啟用了 Htree 索引）和 ext4，它們都有微型加密演算法雜湊過的檔名。為了避免這個問題，Btrfs 每個目錄條目都有一個 目錄索引項，其項的鍵值被設定為一個每個目錄遞增的計數器。因此，對這些索引項的迭代大致按照儲存在磁碟上的相同順序返回條目。 在多個目錄中具有硬連結的檔案有多個引用項，每個父目錄一個。在同一目錄中具有多個硬連結的檔案將所有連結的檔名打包到同一個引用項中。這是一個設計缺陷，它將同一目錄中的硬連結數量限制為多少個可以放入單個樹塊中。（在預設塊大小為 4 KiB、平均檔名長度為 8 位元組和每個檔名頭部為 4 位元組的情況下，這將少於 350 個。）觀察到大量使用同一目錄中多個硬連結的應用程式，在這個限制下會失敗，例如 git、GNUS、GMame 和 BackupPC。 這個限制最終被移除（截至 2012 年 10 月已經合併等待在 Linux 37 中釋出）透過引入溢位的 擴充套件引用項 來儲存不適合的硬連結檔名。 區段 檔案資料儲存在樹外的 區段 中，它們是連續的磁碟資料塊。區段塊預設大小為 4 KiB，沒有頭部，只包含（可能壓縮的）檔案資料。在壓縮的區段中，單個塊不是單獨壓縮的；相反，壓縮流跨越整個區段。 檔案有 區段資料項 來跟蹤儲存其內容的區段。項的鍵值是區段的起始位元組偏移量。這使得在具有多個區段的大檔案中進行有效的尋找，因為任何給定檔案偏移量的正確區段可以用一個樹查詢來計算。 快照和克隆檔案共享區段。當一個大的這樣的區段的一小部分被覆蓋時，結果的寫時複製可能建立三個新的區段：一個小的包含被覆蓋的資料，和兩個大的包含覆蓋兩邊未修改的資料。為了避免重寫未修改的資料，寫時複製可能會建立 書籤區段，或者只是現有區段的切片。區段資料項允許這樣做，透過包含一個到它們正在跟蹤的區段的偏移量：書籤項是那些具有非零偏移量的項。 區段分配樹 區段分配樹 充當檔案系統的分配對映。與其他樹不同，這個樹中的項沒有物件 id。它們表示空間區域：它們的鍵值儲存了它們所代表的區域的起始偏移量和長度。 檔案系統將其分配的空間劃分為 塊組，它們是可變大小的分配區域，交替地偏好元資料區段（樹節點）和資料區段（檔案內容）。資料和元資料塊組的預設比例是 12。它們旨在使用奧爾洛夫塊分配器的概念來分配相關檔案，並透過在組之間留下空閒空間來抵抗碎片化。（然而，Ext3 塊組有固定的位置，是根據檔案系統的大小計算出來的，而 Btrfs 中的塊組是動態的，並根據需要建立）每個塊組都與一個 塊組項 相關聯。檔案系統樹中的 inode 項包含對它們當前塊組的引用。 區段項 包含一個到佔用該區段的樹節點或檔案的反向引用。如果區段在快照之間共享，可能有多個反向引用。如果有太多的反向引用不能適合於項中，它們會溢位到單獨的 區段資料引用項 中。反過來，樹節點也有對它們所包含的樹的反向引用。這使得透過對一對括住該區域的偏移量進行 B 樹範圍查詢，然後跟隨反向引用，可以找到任何空間區域中的哪些區段或樹節點。對於重新定位資料，這允許從重新定位的塊進行有效的向上遍歷，快速找到並修復對這些塊的所有向下引用，而不必掃描整個檔案系統。這反過來又允許檔案系統有效地線上縮小、遷移和碎片整理其儲存。 區段分配樹，與檔案系統中的所有其他樹一樣，是寫時複製的。寫入檔案系統可能會導致一個級聯，其中改變了樹節點和檔案資料導致新的區段被分配，導致區段樹本身發生變化。為了避免建立一個反饋迴路，仍然在記憶體中但尚未提交到磁碟的區段樹節點可以就地更新，以反映新複製的寫時複製區段。 從理論上講，由於區段分配樹充當了一個 B 樹版本的 BSP 樹，因此不需要傳統的可用空間點陣圖 。但實際上，為了加速分配，使用了頁大小點陣圖的紅黑樹。這些點陣圖被持久化到磁碟（從 Linux 2637 開始，透過 space_cache 掛載選項）作為特殊的區段，它們不受校驗和和寫時複製的影響。 校驗和樹和擦除 對資料和元資料都計算 CRC32C 校驗和，並存儲為 校驗和樹 中的 校驗和項。元資料校驗和有 256 位的空間，而資料校驗和最多可以有一個完整的節點（大約 4 KB 或更多）。Btrfs 有為未來版本的檔案系統新增額外的校驗和演算法的計劃。 每個連續的已分配塊都有一個校驗和項，每個塊的校驗和緊密地打包到項資料中。如果有太多的校驗和不能適合，它們會溢位到一個新葉子中的另一個校驗和項中。如果檔案系統在讀取一個塊時檢測到一個校驗和不匹配，在內部映象或 RAID 技術正在使用的情況下，它首先嚐試從另一個裝置獲取（或建立）這個塊的一個好的副本。 Btrfs 可以透過觸發一個在後臺執行的檔案系統擦除作業來啟動對整個檔案系統的線上檢查。擦除作業掃描整個檔案系統的完整性，並自動嘗試報告和修復它在沿途發現的任何壞塊。 塊和裝置樹 塊裝置被劃分為 1 GiB 用於資料的物理塊，和 256 MiB 用於元資料的物理塊。多個裝置上的物理塊可以映象或條帶化成一個單一的 邏輯塊。這些邏輯塊被組合成一個單一的邏輯地址空間，供檔案系統的其餘部分使用。 塊樹 透過將其中的每個裝置儲存為一個 裝置項 和邏輯塊作為 塊對映項 來跟蹤這一點，，提供了從邏輯到物理地址的正向對映。塊對映項可以是以下幾種型別之一： single 1 個邏輯到 1 個物理塊 dup 1 個邏輯塊到 1 個塊裝置上的 2 個物理塊 raid0 N 個邏輯塊到 N2 個裝置上的 N2 個物理塊 raid1 1 個邏輯塊到 N2 個裝置中的 2 個物理塊，與傳統的 RAID 1 不同，它有 N 個物理塊 raid1c3 1 個邏輯塊到 N3 個裝置中的 3 個物理塊；raid1c4 1 個邏輯塊到 N4 個裝置中的 4 個物理塊；raid5 N（對於 N2）個邏輯塊到 N1 個裝置上的 N1 個物理塊，其中 1 個物理塊用作奇偶校驗；raid6 N（對於 N2）個邏輯塊到 N2 個裝置上的 N2 個物理塊，其中 2 個物理塊用作奇偶校驗 N 是在分配塊時仍然有空閒空間的塊裝置的數量。如果 N 對於選擇的映象 對映不夠大，那麼檔案系統就有效地沒有空間了。 重定位樹 碎片整理、縮小和重新平衡操作需要重新定位區段。然而，對正在重新定位的區段進行簡單的寫時複製將破壞快照之間的共享並消耗磁碟空間。為了保持共享，使用一個更新和交換演算法，一個特殊的重定位樹作為受影響的元資料的臨時空間。首先將要重新定位的區段複製到它的目的地。然後，透過沿著受影響的子卷的檔案系統樹向上跟隨反向引用，逐漸更新指向舊區段的元資料，使其指向新的區段；任何新更新的項都儲存在重定位樹中。一旦更新完成，重定位樹中的項與受影響子卷中的對應項交換，然後丟棄重定位樹。 超級塊 檔案系統中的所有樹 包括塊樹本身 都儲存在塊中，這會產生一個引導問題，當掛載檔案系統時。為了引導到一個掛載點，塊樹和根樹所屬的塊的物理地址列表儲存在超級塊中。 超級塊映象儲存在固定位置：每個塊裝置 64 KiB 處，以及 64 MiB、256 GiB 和 1 PiB 處的額外副本。當更新一個超級塊映象時，它的生成號遞增。在掛載時，使用生成號最高的副本。除了 SSD 模式，所有超級塊映象都同時更新；而在 SSD 模式下，為了提供一定程度的磨損平衡，超級塊映象之間交替更新。 參考資料 參見 檔案系統的對比 ZFS ext4 Tux3 外部連結 Initial Btrfs 宣告 Coherent 遠端檔案系統，基於 btrfs 新一代 Linux 檔案系統 btrfs 簡介 Category 磁碟檔案系統 Category 電腦資料 CategoryLinux 檔案系統 CategoryMeeGo