Btrfs

Btrfs。Btrfs也宣稱專注在“容錯、修復及易於管理”。歷史.Btrfs的核心資料結構——寫時複製B樹——最初是由IBM研究員Ohad Rodeh在2007年USENIX會議上提出的。Chris Mason當時是SUSE公司的ReiserFS工程師，後來加入了Oracle，並開始開發一種基於B樹的新檔案系統。2008年，ext3和ext4檔案系統的主要開發者曹子德表示，雖然ext4有改進的功能，但它不是一個重大的進步；它使用了舊技術，是一個權宜之計。曹子德說，Btrfs是一個更好的方向，因為“它在可擴充套件性、可靠性和易管理性方面提供了改進”。Btrfs也有“一些與reiser3/4相同的設計思想”。Btrfs 1.0版本具有最終確定的磁碟格式，於2008年底釋出，並於2009年被接受進入Linux核心主線。幾個Linux發行版開始在安裝過程中提供Btrfs作為根檔案系統的實驗性選擇。2011年7月，Btrfs自動碎片整理和擦除功能被合併到Linux核心主線的3.0版本中。除了Oracle的Mason外，富士通的Miao Xie也貢獻了效能改進。2012年6月，Chris Mason離開Oracle加入Fusion-io，一年後又與Josef Bacik一起加入Facebook。在這兩家公司工作期間，Mason繼續他對Btrfs的工作。2012年，兩個Linux發行版將Btrfs從實驗性狀態轉變為生產或支援狀態：3月份的Oracle Linux ，8月份的SUSE Linux Enterprise 。2015年，Btrfs被採用為SUSE Linux Enterprise Server12的預設檔案系統。2017年8月，紅帽公司在Red Hat Enterprise Linux，並指出它將在RHEL 7釋出系列中保持可用。2019年5月，Btrfs從RHEL 8中移除。RHEL從RHEL 6中的ext4轉移到RHEL 7中的XFS。2020年，Btrfs被選為Fedora 33桌面變體的預設檔案系統。特性.克隆.Btrfs 提供了一個克隆操作，可以原子地建立一個檔案的寫時複製快照。這樣的克隆檔案有時被稱為 codice_1，因為它們與擬議的相關 Linux 核心系統呼叫有關。在克隆時，檔案系統不會建立一個指向現有 codice_2 的新連結；相反，它會建立一個新的 codice_2，最初與原始檔案共享相同的磁碟塊。因此，克隆只能在同一個 Btrfs 檔案系統的邊界內工作，但是在某些情況下，自 Linux 核心 3.6 版本起，它可能會跨越子卷的邊界。實際的資料塊不會被複制；同時，由於 Btrfs 的寫時複製特性，對任何克隆檔案的修改都不會在原始檔案中可見，反之亦然。克隆不應與硬連結混淆，硬連結是將多個檔名與單個檔案關聯的目錄項。雖然硬連結可以被認為是同一檔案的不同名稱，但 Btrfs 中的克隆提供了最初共享所有磁碟塊的獨立檔案。GNU coreutils 自 7.5 版本支援了這個 Btrfs 特性，透過 codice_4 命令的 codice_5 選項可以使用克隆功能。除了資料克隆相同資料的檔案共享儲存空間。子卷和快照.Btrfs子卷可視為一個單獨的POSIX檔案名稱空間，向codice_6命令傳遞codice_7或codice_8選項能夠單獨掛載相對應的子卷。其他子卷也可以透過掛載頂層子捲來訪問，此時其他子卷作為頂層子卷的子目錄供使用者訪問。子卷可以在檔案系統層次結構中的任何位置建立，也可以巢狀。巢狀的子卷在其父子卷中顯示為子目錄，類似於頂層子卷將其他子卷顯示為子目錄的方式。刪除一個子卷前，需要確保該子卷內不存在巢狀的子卷；因此，不能刪除頂層子卷。Btrfs檔案系統有一個預設子卷，最初設定為頂層子卷，在傳遞子卷選擇選項時預設掛載。預設子卷可以根據需要更改。Btrfs快照是一個與其他子卷共享資料的子卷，使用Btrfs的寫時複製實現，對快照的修改在原始子卷中不可見。可寫的快照可以視為原始檔案系統的一個副本。例如，要回滾到一個快照，可以解除安裝修改過的原始子卷，並將快照掛載到它的位置來實現。此時，也可以刪除原始子卷。Btrfs的寫時複製特性意味著快照可以快速建立，同時剛剛建立時僅消耗很少的磁碟空間。由於快照是一個子卷，因此也可以建立巢狀的快照。對一個子捲進行快照不是一個遞迴的過程；因此，如果建立了一個子卷的快照，該子捲包含的每個巢狀子卷都會對映到同名的空目錄中。不能對一個目錄進行快照，只有子卷才能有快照。然而，有一種涉及跨越子卷的reflinks的解決方案：建立一個新的子卷，包含指向目標目錄內容的跨越子卷的reflinks。有了這個，就可以建立這個新卷的快照。Btrfs中的子卷與傳統的LVM邏輯卷非常不同。在LVM中，邏輯卷是一個單獨的塊裝置，而Btrfs子卷更類似於POSIX名稱空間。原始或副本中的任何一個在同一臺計算機上掛載時，對btrfs進行dd或LVM快照會導致資料丟失。子卷傳送與接收.給定任意一對子捲了將一個子卷轉換為另一個子卷所需的一組資料修改。傳送/接收功能可以與定期安排的快照一起使用，用於實現檔案系統複製的簡單形式，或用於執行增量備份。配額組.配額組可以對一個子卷或快照可能消耗的空間設定上限。新的快照最初不消耗配額，因為它的資料與其父卷共享，但之後會因為新檔案和對現有檔案的寫時複製操作而產生空間上的開銷。當配額功能啟用時，每個新的子卷或快照都會自動建立一個配額組。這些初始的配額組是可以分組成層次結構來實現配額池的構建塊。配額組只適用於子卷和快照，而不能對單個子目錄、使用者或使用者組強制執行配額。然而，可以透過使用不同的子捲來實現所有需要強制執行配額的使用者或使用者組。原地轉換ext2/3/4和ReiserFS.由於在固定位置的元資料非常少，Btrfs可以適應後端儲存裝置的各種的空間佈局。codice_12工具可以透過在其未分配空間中巢狀等效的Btrfs元資料——同時保留原始檔案系統的未修改副本，即原地轉換一個ext2/3/4或ReiserFS檔案系統。轉換需要建立整個ext2/3/4元資料的副本，而Btrfs檔案只是指向與ext2/3/4檔案使用的相同的塊。這使得在不可逆轉換之前，兩個檔案系統共享大部分塊。由於Btrfs的寫時複製特性，在所有檔案修改過程中，原始版本的檔案資料塊都保持不變。在不可逆轉換之前，只有在ext2/3/4中標記為空閒的塊才用於儲存新的Btrfs修改，這意味著轉換可以隨時撤銷轉換。所有轉換後的檔案都在Btrfs的預設子卷中。轉換工具會在一個單獨的子卷中建立包含對原始ext2/3/4檔案系統所有引用的稀疏檔案；這一檔案可以作為一個只讀磁碟映像單獨掛載，允許同時訪問原始檔案系統和轉換後的檔案系統。刪除這個稀疏檔案會釋放原有檔案系統額外佔用的空間，並使轉換變得不可逆。在主線Linux核心的4.x版本中，就地ext3/4缺乏使用與測試，不能保證穩定性。然而，該功能在2016年的codice_13 4.6從頭重寫。Btrfs的就地檔案系統轉換功能自此宣佈穩定。就地從ReiserFS轉換在2017年9月引入到Linux 4.13核心中。聯合掛載/種子裝置.在建立一個新的Btrfs時，可以使用一個已存在的Btrfs作為一個只讀的“種子”檔案系統。新的檔案系統將作為種子上的一個寫時複製覆蓋層，作為一種聯合掛載的形式。種子可以稍後從Btrfs中分離，在此之前，重平衡器將簡單地複製任何仍然被新檔案系統引用的種子資料，然後分離。Btrfs的主要貢獻者Mason認為這可能對Live CD安裝程式有用，它可以從光碟上的一個只讀Btrfs種子啟動，在使用者繼續工作的同時，在後臺將自己重平衡到安裝磁碟上的目標分割槽，然後彈出光碟以完成安裝而不需要重新啟動。加密.在2009年的採訪中，Chris Mason表示計劃為Btrfs增加加密支援。目前，將加密與Btrfs結合使用的一種解決方案是使用諸如dm-crypt / LUKS之類的全盤加密機制在底層裝置上，並在該層之上建立Btrfs檔案系統。截至2020年 (2020)[ [update]]開發人員正在努力新增類似HMAC的鍵控雜湊。檢查和恢復.Unix系統傳統上使用fsck程式來檢查和修復檔案系統。這個功能是透過codice_14程式實現的。從4.0版本開始，這個功能被認為是相對穩定的。然而，截至2023年6月，btrfs文件建議只有在“開發者或經驗豐富的使用者”建議時才使用其codice_15選項。截至2023年6月，SLE文件建議使用一個Live CD，執行一個備份，並只在最後的手段時使用修復選項。還有另一個工具codice_16，可以用於從一個不可掛載的檔案系統中恢復檔案，而不修改損壞的檔案系統本身。在正常使用中，Btrfs基本上是自我修復的，並且可以在掛載時從損壞的根樹結構中恢復，這是因為預設每30秒向永久儲存重新整理資料。因此，孤立的錯誤會導致下一次掛載時最多30秒的檔案系統更改丟失。這個週期可以透過在codice_17掛載選項中指定所需的值來更改。設計.Ohad Rodeh在2007年的USENIX提出的原始方案指出，廣泛用作資料庫的磁碟資料結構的B+樹不能有效地實現基於寫時複製的快照，因為它的葉子節點是連線在一起的：如果一個葉子被寫時複製，它的兄弟節點和父節點也必須如此，以及它們遞迴的兄弟和父節點，直到整個樹被複制。他建議使用一個修改過的B樹，並且每個樹節點都有一個引用計數，但是儲存在一個專門的自由對映結構中，並且對樹的平衡演算法進行了一定的放鬆，使它們對寫時複製友好。結果將是一個適合高效能物件儲存的資料結構，可以執行寫時複製快照，同時保持良好的併發性。在當年晚些時候在Oracle工作的Chris Mason開始了一個能夠使用這種資料結構的快照能力檔案系統的工作，幾乎完全採用這種資料結構——不僅用於元資料和檔案資料，而且遞迴地用於跟蹤樹本身的空間分配。這允許所有遍歷和修改都透過同一份程式碼，只需要實現一次諸如寫時複製、校驗和和映象等特性，就可以在整個檔案系統的各個地方使用。Btrfs是由這樣的樹組成的幾層結構，所有這些樹都使用相同的B樹實現。樹儲存了按照136位鍵排序的通用“項”。鍵中最重要的64位是一個唯一的“物件id”。中間8位是一個項型別欄位：它的用法是硬編碼到程式碼中作為樹查詢中的項過濾器。“物件”可以有多個型別的多個項。剩下的64位以型別特定的方式使用。因此，同一物件的項會在樹中彼此相鄰，按型別分組。透過選擇某些鍵值，物件可以進一步按照特定順序放置同一型別的項。內部樹節點只是鍵-指標對的平面列表，其中指標是子節點的邏輯塊號。葉節點包含打包到節點前面的項鍵和打包到節點末尾的項資料，在葉填充時兩者向彼此增長。檔案系統樹.在每個目錄中，目錄條目以“目錄項”的形式出現，它們的鍵值的最不重要的位是它們檔名的CRC32C雜湊。它們的資料是一個“位置鍵”，或者是它指向的inode項的鍵。目錄項一起可以作為路徑到inode查詢的索引，但不用於迭代，因為它們按照它們的雜湊排序，有效地隨機排列它們。這意味著在一個大目錄中迭代和開啟檔案的使用者應用程式將產生更多的磁碟尋道，因此在非相鄰檔案之間尋道——這是其他檔案系統中具有雜湊排序目錄的顯著效能損耗，例如ReiserFS， ext3和ext4，它們都有微型加密演算法雜湊過的檔名。為了避免這個問題，Btrfs每個目錄條目都有一個"目錄索引項"，其項的鍵值被設定為一個每個目錄遞增的計數器。因此，對這些索引項的迭代大致按照儲存在磁碟上的相同順序返回條目。在多個目錄中具有硬連結的檔案有多個引用項，每個父目錄一個。在同一目錄中具有多個硬連結的檔案將所有連結的檔名打包到同一個引用項中。這是一個設計缺陷，它將同一目錄中的硬連結數量限制為多少個可以放入單個樹塊中。觀察到大量使用同一目錄中多個硬連結的應用程式，在這個限制下會失敗，例如git、GNUS、GMame和BackupPC。這個限制最終被移除透過引入溢位的"擴充套件引用項"來儲存不適合的硬連結檔名。區段.檔案資料儲存在樹外的“區段”中，它們是連續的磁碟資料塊。區段塊預設大小為4 KiB，沒有頭部，只包含檔案資料。在壓縮的區段中，單個塊不是單獨壓縮的；相反，壓縮流跨越整個區段。檔案有“區段資料項”來跟蹤儲存其內容的區段。項的鍵值是區段的起始位元組偏移量。這使得在具有多個區段的大檔案中進行有效的尋找，因為任何給定檔案偏移量的正確區段可以用一個樹查詢來計算。快照和克隆檔案共享區段。當一個大的這樣的區段的一小部分被覆蓋時，結果的寫時複製可能建立三個新的區段：一個小的包含被覆蓋的資料，和兩個大的包含覆蓋兩邊未修改的資料。為了避免重寫未修改的資料，寫時複製可能會建立“書籤區段”，或者只是現有區段的切片。區段資料項允許這樣做，透過包含一個到它們正在跟蹤的區段的偏移量：書籤項是那些具有非零偏移量的項。區段分配樹.“區段分配樹”充當檔案系統的分配對映。與其他樹不同，這個樹中的項沒有物件id。它們表示空間區域：它們的鍵值儲存了它們所代表的區域的起始偏移量和長度。檔案系統將其分配的空間劃分為“塊組”，它們是可變大小的分配區域，交替地偏好元資料區段每個塊組都與一個“塊組項“相關聯。檔案系統樹中的inode項包含對它們當前塊組的引用。“區段項”包含一個到佔用該區段的樹節點或檔案的反向引用。如果區段在快照之間共享，可能有多個反向引用。如果有太多的反向引用不能適合於項中，它們會溢位到單獨的“區段資料引用項“中。反過來，樹節點也有對它們所包含的樹的反向引用。這使得透過對一對括住該區域的偏移量進行B樹範圍查詢，然後跟隨反向引用，可以找到任何空間區域中的哪些區段或樹節點。對於重新定位資料，這允許從重新定位的塊進行有效的向上遍歷，快速找到並修復對這些塊的所有向下引用，而不必掃描整個檔案系統。這反過來又允許檔案系統有效地線上縮小、遷移和碎片整理其儲存。區段分配樹，與檔案系統中的所有其他樹一樣，是寫時複製的。寫入檔案系統可能會導致一個級聯，其中改變了樹節點和檔案資料導致新的區段被分配，導致區段樹本身發生變化。為了避免建立一個反饋迴路，仍然在記憶體中但尚未提交到磁碟的區段樹節點可以就地更新，以反映新複製的寫時複製區段。從理論上講，由於區段分配樹充當了一個B樹版本的BSP樹，因此不需要傳統的可用空間點陣圖 。但實際上，為了加速分配，使用了頁大小點陣圖的紅黑樹。這些點陣圖被持久化到磁碟作為特殊的區段，它們不受校驗和和寫時複製的影響。校驗和樹和擦除.對資料和元資料都計算CRC-32C校驗和，並存儲為“校驗和樹”中的“校驗和項”。元資料校驗和有256位的空間，而資料校驗和最多可以有一個完整的節點。Btrfs有為未來版本的檔案系統新增額外的校驗和演算法的計劃。每個連續的已分配塊都有一個校驗和項，每個塊的校驗和緊密地打包到項資料中。如果有太多的校驗和不能適合，它們會溢位到一個新葉子中的另一個校驗和項中。如果檔案系統在讀取一個塊時檢測到一個校驗和不匹配，在內部映象或RAID技術正在使用的情況下，它首先嚐試從另一個裝置#重定向 獲取這個塊的一個好的副本。Btrfs可以透過觸發一個在後臺執行的檔案系統擦除作業來啟動對整個檔案系統的線上檢查。擦除作業掃描整個檔案系統的完整性，並自動嘗試報告和修復它在沿途發現的任何壞塊。塊和裝置樹.塊裝置被劃分為1 GiB用於資料的物理塊，和256 MiB用於元資料的物理塊。多個裝置上的物理塊可以映象或條帶化成一個單一的“邏輯塊”。這些邏輯塊被組合成一個單一的邏輯地址空間，供檔案系統的其餘部分使用。“塊樹”透過將其中的每個裝置儲存為一個“裝置項”和邏輯塊作為“塊對映項”來跟蹤這一點，，提供了從邏輯到物理地址的正向對映。塊對映項可以是以下幾種型別之一：raid1c4 : 1個邏輯塊到N≥4個裝置中的4個物理塊 ;raid5 : N個邏輯塊到N+1個裝置上的N+1個物理塊，其中1個物理塊用作奇偶校驗 ;raid6 : N個邏輯塊到N+2個裝置上的N+2個物理塊，其中2個物理塊用作奇偶校驗 “N”是在分配塊時仍然有空閒空間的塊裝置的數量。如果N對於選擇的映象/對映不夠大，那麼檔案系統就有效地沒有空間了。重定位樹.碎片整理、縮小和重新平衡操作需要重新定位區段。然而，對正在重新定位的區段進行簡單的寫時複製將破壞快照之間的共享並消耗磁碟空間。為了保持共享，使用一個更新和交換演算法，一個特殊的重定位樹作為受影響的元資料的臨時空間。首先將要重新定位的區段複製到它的目的地。然後，透過沿著受影響的子卷的檔案系統樹向上跟隨反向引用，逐漸更新指向舊區段的元資料，使其指向新的區段；任何新更新的項都儲存在重定位樹中。一旦更新完成，重定位樹中的項與受影響子卷中的對應項交換，然後丟棄重定位樹。超級塊.檔案系統中的所有樹——包括塊樹本身——都儲存在塊中，這會產生一個引導問題，當掛載檔案系統時。為了引導到一個掛載點，塊樹和根樹所屬的塊的物理地址列表儲存在超級塊中。超級塊映象儲存在固定位置：每個塊裝置64 KiB處，以及64 MiB、256 GiB和1 PiB處的額外副本。當更新一個超級塊映象時，它的生成號遞增。在掛載時，使用生成號最高的副本。除了SSD模式，所有超級塊映象都同時更新；而在SSD模式下，為了提供一定程度的磨損平衡，超級塊映象之間交替更新。