# F2FS and BtrFS
## F2FS
F2FS 全名為 Flash-Friendly File System,由三星 (Samsung) 開發,期望藉由此項目取代傳統的如 JAFFS 等應用於快閃記憶體的檔案系統,在效能上也較 ext4 有更好的表現。
在一個行動裝置上,通常會有多個快閃晶片 (Flash Chips),所以需要透過專門的硬體和軟體如 FTL (Flash Tramslation Layer) 將各種不同的快閃儲存裝置抽象並統一,且通常使用隨機寫入 (random write) 來存取,但會因此衍生一些問題如下:
- 頻繁地隨機寫入會造成嚴重的碎片化
- 對行動裝置來說,隨機寫入會造成較大的負擔
- 增加裝置的 I/O 延遲
- 減少裝置的生命週期 (life time)
因此,F2FS 為了解決這些問題,使用 1. Log-structured 2. COW (Copy on Write) 來解決這些問題。
### 結構
整個檔案系統在磁碟上,由小到大的單位依序是 segment, section, zone,segment 預設的大小為 2MB,並且將 volume 切成多個固定大小的區塊,並配置如下:
1. Superblock:不可變更的,用來儲存基礎的分割資訊,唯一不是以 segment 當作最小單位。
2. Check Point (CP):用來保持文件的狀態,正常情況下,CP 必須在特定的時間儲存一致的狀態,並在突發事件例如斷電、作業系統崩潰後,該單位則成為恢復點 (recovery point)。
4. Segment Info Table (SIT):用來儲存該 segment 的資訊,例如有多少可用的區塊 (valid blocks) 及 bitmap 用來儲存所有區塊 (block) 的狀態等,當需要清理 (cleaning) 時,可藉由此區塊快速的判斷。
5. Node Address Table (NAT):用來儲存在主區域 (main area) 中,所有 node blocks 的地址。
6. Segment Summary Area (SSA):用來儲存所有在主區域中各區塊的資訊如 parent inode number, node offset, data offset...。
7. Main Area:該區域為儲存裝置的主要資料儲存區,並且有兩種型態的節點 (node)
- node:該資料區塊的 inode 或是作為 indirect inode
- data:使用者儲存的資料或是目錄 (directory)
![](https://i.imgur.com/hNxorLe.png)
### 索引結構 (index structure)
主要可分為檔案結構 (file structure) 和目錄結構 (directory structure)。
- 檔案結構 (File Structure):傳統的 LFS (Log-structured File System) 透過 inode 映射到對應的實體位址 (physical location),但 F2FS
- 目錄結構 (Directory Structure):為一個 4KB 大小的 dentry,由 bitmap, 兩個陣列紀錄 slot 和名稱。bitmap 用來記錄每一個 slot 是否有效;slot 紀錄 hash value、inode number、檔案長度、檔案類別等資訊。一個目錄結構會採用多層 hash table 的結構來管理。
### Multi-head Logging
該檔案系統使用 6 個 major log areas 標示 hot/cold 數據,一般的檔案系統會直接使用一大塊的 log areas 紀錄。實際上使用者可以自行決定要使用 2、4、6 種標示。如果使用 4 種,則會將 warm 和 cold 合併為一個標是;如果使用 2 種,則只會區分為 node 或是 data。
- direct node:和一般的定義相同,使用上會比 indirect node 更頻繁一些,因為該類型的 node 會直接接觸,所以會頻繁地更新資料,因此標示上為 Hot 和 Warm。
- indirect node:負責紀錄 directo node 的位址,只有在新增或是刪除節點的時候會更新,因此標示為 Cold。
- Main area 中目錄的 direct node 和 data block 都會被標示為 hot。
- 至於其他的 data block 只要符合下列其中一個條件,即可被標示為 Cold:
- 該 block 經過清理 (Cleaning) 移動過,可參考後續部分。
- 使用者可以自行定義該 block 為 Cold。
- 多媒體類型的資料也會被標示為 Cold,因為多媒體類型的資料通常寫入後不會頻繁地更新。
![](https://i.imgur.com/bfIRXIn.png)
### 清理 (Cleaning)
用來整理破碎化、無效的區段 (segment) 的機制,每次清理會以 section 為最小單位來做清理。總共會分成兩種方法來做清理,分別是前景 (front-ground) 和背景 (back-ground),前景只會在沒有足夠的空間時才會使用;背景則是會定期實施。可分為下列三步驟:
1. Victim Selection,選擇要清理的 section。
- greedy:前景 (front-ground) 時使用的方法,假設有 10 個 sections,在這十個 sections 中找出 valid blocks 最少的 section,代表該 section 的使用率 (utilization) 最低。
- cost-benefit:背景 (back-ground) 時使用的方法,以使用率和 age 來當作標準,age 為最近一次該 block 修改的時間,而該資訊會記錄在 SIT 中,此外也可以藉由 hot/cold 的標示迅速獲得。
2. valid block identification and migration:辨識有效的 block 並整合進其他 section 中。
- 前景使用的方法:檔案系統會使用一組 bitmap 來記錄每個 segment 的是否為有效的 (valid),且該 bitmap 會放置在 SIT 中,因此只要掃瞄 SIT 即可得知每個 segment 內部的情況,在掃描完 bitmap 後,直接將 valid block 搬移至其他 section 中閒置的位置。如此即可空出一條完整的 secton 可寫入。(搬移的同時也會處理 parent node block 和其他相關的訊息)
- 背景使用的方法:檔案系統本身不會親自執行搬移的動作,而是將 valid block 推到 page cache 中,並且標示為 dirty,kernel 會在下次發生 cache misses 時,首先將 dirty block 移入檔案系統中。
3. post-cleaning process:在步驟 2. 之後會將 section 標記為 candicate (pre-free),但還不能夠被使用,經過 CP 運作後,才會標記為 free 並且被使用。這個步驟主要是為了避免斷電或是系統崩潰之類的事情發生。
## Adaptive Logging
該部分主要探討檔案系統如何將資訊寫入至檔案系統中。主要有兩種策略如下:
- normal logging:block 被寫入到完整乾淨的 segment 中,並且以循序寫入 (sequential write) 的方式寫入,不論系統提出任何隨機寫入 (random write) 的要求。所以當空間耗盡時,就會一直發生清理 (cleaning)。
- threaded logging:將資料寫入到非完整的 segment 的空閒的 block 中,但因為採用隨機寫入 (random write) 所以效能表現較差。
F2FS 會實作上樹兩種機制,並且動態的改變策略,以目前擁有 k 個乾淨的 section 作為判斷標準,k 為預先設定好的閥值,通常為所有 section 數目中的 5%。
## BtrFS
由 Oracle 公司在 2017 年研發,原本是打算由此檔案系統替換掉 Linux 中 ext 系列的檔案系統,但由於設計問題,一直沒有長期支持的版本 (LTS)。
- page, block:block 為 4KB 的大小,並且是連續空間。
- Extent:許多檔案系統也會用到該概念,在磁碟上一塊連續的空間,並且對齊 page,所以長度為 page 的倍數,因為檔案系統通常是連續分配的,用此制度可以大幅的減少管理檔案空間的開銷,例如在 ext3 上,每增加一個 1GB 的檔案需要 256KB 大小的空間存放 block 管理。
- Copy-on-Write (COW):此機制也是常用的方法,一般檔案系統在複製的時候會直接使用額外的空間存放複製的內容。但此機制是將此區域設為 read-only,當有 process 試著寫入時,才會配置一塊空間並複製內容供該 process 使用。
### 設計
1. COW friendly B-trees:使用 B-tree 結構,並且遵守下列三個特性
- top-down update procedure:由上至下更新。
- remove leaf-chaining:將不必要的節點清除。
- 使用計數器 (counter) 來管理空間:紀錄有多少個節點指向自己,可參考複製的說明和範例。樹根皆為 1,因為檔案系統會由一個 root 指向各樹的 root。
- 加入:可參考下圖解說,圖(a)為基本的 B-tree 結構範例,當要插入一個新的資料 19 時,並不會直接寫入到該寫入的 node 中,而是先複製一塊一樣的資料,並且複製一塊新的父節點,在寫入資料後,之後再將新的父節點的鏈結 (link) 連至新的節點。可對照至 top-down update procedure。
![](https://i.imgur.com/DHK3PuQ.png)
- 刪除:可參考下圖解說,圖(a)為一基本的 B-tree 結構範例,當要刪除一個新的資料時,操作和寫入類似,會有一個新的父節點,複製一塊一樣的子節點,並且在新的節點上刪除後再鏈結。
![](https://i.imgur.com/xUFvs0m.png)
- 複製:可參考下圖解說,當有一父節點 p,並且新創建一節點 Q 複製節點 p。新舊復節點會同時連結同一節點一段時間,主要是為了避免發生斷電或是系統崩潰,造成無法恢復。此外這部分還增加了 ref-counter,也就是前面提到的計數器,主要是用來記錄被多少個節點指向自己。
![](https://i.imgur.com/rhG7CB2.png)
- 清除:可參考下圖解說,當執行完複製或是相關行為後,會將複製的副本節點刪除,這時會先將該節點的父節點的計數器 (ref-counter) 標示為 0,並且一步步地往下更新各節點的計數器,並且最後在(c)步驟將計數器歸零的節點刪除。
![](https://i.imgur.com/6ahsoti.png)
透過這些行為可對應上述的三個特性。
## 特性
該檔案系統的 superblock 會在固定的硬碟位址,並且指向 樹根 (root)。BtrFS 可視為由多個 B-tree 組成的森林結構。
- subvolume:該結構負責保存用戶可見的文件和目錄的訊息,同時該結構也是一個 B-tree。該結構可以達成 Snapshot (藉由 COW 機制)。藉由 subvolume,可以將整個檔案系統切割成多個 subvolume,再整合成一個森林來進行管理,可參考下圖。
![](https://i.imgur.com/nT6efGl.png)
- snapshot:將現在目前的結構,包含連結關係等記錄起來,但不對結構做任何事,在需要進行復原 (recovery) 時,可藉由最新的 snapshot 來進行復原。
- checksum:檔案系統也會進行一致性檢查。
- shadow:基於 COW 的複製服務,並不會直接配置一塊位置並且進行複製,而是在有資料變更時才複製。
---
## F2FS
Flash-friendly file system
專門為 NAND flash 設計的檔案系統
一個 mobile device 上通常會有多個 flash chips ,所以需要透過專門的硬體 (controller) 和軟體 FTL (Flash Translation Layer) 將各種不同的 flash storage 來抽象並統一。通常會使用 random write 來存取,但會衍生一些問題如下:
- 頻繁地 random wrtie 會造成嚴重的碎片化
- 對 mobile device 來說,random write 負擔較大。
- 增加 I/O latency
- 減少裝置的 lifetime
因此可以透過 1. Log-structured FS 2. COW (Copy on write) 機制來解決。
:::info
快閃記憶體有兩種型別,NOR 和 NAND,NOR 常用在 BIOS ROM 裡面。而 NAND 則是用在常見的 SSD, SDcard ... 產品上,此外又有顆粒分別如 TLC, MLC, QLC 等
block access, 最基本的存取單位,讀取或寫入可以以 block 為 offset
抹除的話則是以 "頁" 為單位。
:::
### feature
1. 一種快閃記憶體檔案系統
2. 採用 log structured file system approach 實作,也有盡量避免一些在既有 log structured FS 的問題如 snowball effect of wandering tree, high cleaning overhead。^[2]^
3. 缺點: erase-before-write requirement,
### Design of F2FS
1. Flash-freindly on-disk layout
- segments, sections, zones
- 將 volume 切割成多個 fixed-size segements
- superblock: not changable, 基礎的分割 (partition) info
- checkpoint: 保持文件的狀態,正常無被破壞的 CP 必須在給定的時間儲存一致的 F2FS 狀態,並在突發事件如斷電等之後,該 CP 則成為 recovery point。使用兩個 segment,一個為 Last stable, 一個為 intermediate
- segment info table
- node address table
- segment summary area: 儲存所有區塊的資訊例如 parent inode number, node/data offset 等
- main area: 有兩種 type: data/node, 同一個 section 不會同時有 data 和 node。也就是說最小單位是 section。
- 示範如何完成 search "file":
1. NAT 會告知 root inode 位置
2. 在 root inode block 找名為 "file" 的 data block 和 inode number
3. 透過 NAT 找到該 inode number 的 physical 位址
4. 讀取該區塊得到 inode 的位址
5. 在 "file" 的 inode 重複 3,4 來找到要找的東西
3. Cost-effective index structure
- file structure: 傳統的 LFS 透過 inode 映射到 physical location,但 F2FS 透過 node 來擴展,node 總共有三種型態 inode (包含 file's metadata(file name, file size...)), direct node(包含data 的 block address), indirect node 包含另一個 node 的 address。使用 pointer-based 來實作 direct/indirect node,所以比起 LFS ,在加入一個 data 到 file(8MB-4GB or bigger than 4GB),F2FS 都只需要更新一個 pointer。
- Directory structure: 一個 4KB 的 dentry 由 bitmap, two arrays of slots, names in pairs 組成。bitmap 代表每一個 slot 是否有效,slot 紀錄 hash value, inode number, len of file, file type。一個 directory 會建立 multi-level hash tables 來管理。 dentry 算是很重要的一個結構,會放進 cache 裡面當作快取,詳細的可以參考 VFS 的一些實作。
4. Multi-head logging
用 6 major log areas 去分離 hot/cold 數據。如果使用 6 個來紀錄,則可依照表 1 去紀錄,如果用 4 個(user 可以自己決定要用多少個) 會將 cold 和 warm 合併起來。如果只使用 2 個來紀錄,則一個紀錄 node 另一個紀錄 data。傳統的 LFS 只使用一個 log area 來紀錄。
- direct node: 比 indirect node 更熱一點,因為他會頻繁地更新。
- indirect node: 紀錄 node IDs (可參考前面),只有在新增或刪除的時候會更動。
- directory's direct node and data blocks 都被認為 hot。和常規 data block 相比,這兩者的寫入明顯比較頻繁(畢竟是目錄使用的)。
- data blocks 只要符合下列三者即可被認為是 cold:
- data blocks moved by cleanning: 可以參考 4. ,預設再經過 clenning 操作後,會維持一段時間。
- data blocks labeled "cold" by the user: 算是 F2FS 支援的操作。比較特別一點
- multimedia file data: 基本上很少會一直更動這類型的檔案,所以 F2FS 預設他為 cold。
最後在和 FTL 的配合上也有一些考慮,不過這邊就先跳過吧==
4. Cleaning
用來整理 分散、無效的區段的 process。以 section 為單位來做清理。
有兩種整理的方法,front-ground 和 back-ground, front 只有在沒有足夠的 section 時才會出現。back 則會定期實施。3 steps:
1. victim selection: 在非空的 sections 中找尋目標 (section)
- greedy: 假設有 10 個 sections,在這十個中找擁有最少有用 block 的 section。所以 overhead 為該 section 中 valid block 的時間。在 F2FS 的 front-ground 使用這種方法。簡單來說就是以 utilization 來當作選擇的標準。
- cost-benefit: 以 utilization 和 age 來當作標準,應用在 back-ground 。 age 可以從 SIT 根據最後修改時間獲得,此外也可以藉由這個機制將資料標示為 hot / cold data。
2. valid block identification and migration: 挑選 section 後,要整理該 section 中的 block。
- F2FS 會使用一組 bitmap 來記錄每個 segment 的 valid 狀況 (放置在 SIT 內),所以只要掃過該 SIT 即可。F2FS 在掃描整個 bitmap 後 (也會掃描 parent node block,parent node 通常是 valid),會將 valid block 搬移至其他的 section,這樣就空出一整條完整的 section 。
- back-ground 的方法(有點神奇),他不親自搬移 blocks,而是將 block 推到 page cache 並且標示為 dirty (也就是會被 page cache 淘汰,藉由 kernel 的機制),等下次 page cache 不夠空間需要清除時,會將該 block 移動回去 FS。僅會在閒置時使用。
3. post-cleaning process: 在步驟2. 之後會將該 section 標記為 candicate (pre-free),經過 CP 之後才會變成 free section。是為了避免斷電之類的事情。
5. Adaptive logging: 寫入的方式
傳統的 LFS 有兩種 policy 如下。
- normal logging: block 被寫入到 clean segment 中,並且以 sequential write 的方式寫入,不論提出任何 random 的要求。所以當 free space 耗盡的時候,就會一直發生 cleaning。
- threaded logging: 將 block 寫入到 hole (invalid, obsolete space) 到現有的 dirty segment 中。但因為是 random write,所以會降低 performance。
- F2FS 會實作上述兩種機制,並且動態的改變 policy,以 k clean section 當作判斷依據(k 為 pre-defined,通常為 5% of total sections)。 thread logging 有可能會造成不良的隨機寫入,但有 paper 證明在 flash 上不會有這問題。
7. `fsync` acceleration with roll-forward recovery
實作一個 CP 機制來確保一致性,會在下列程序後啟動 (triger) 1. 所有的 dirty node/page 都從 cache flush 到 Storage 中。2. 暫停所有寫入的活動如 create mkdir 之類的。3. 所有 FS 的 metadata 如 NAT SIT SSA 都被寫入到該寫入的位置。4. 完成上述後,才會開始建立 CP pack 並寫入下列資訊到 CP area 中
- header and footer: 會放在 pack 的頭尾,用來記錄版本號,每次更新都會疊加上去
- NAT and SIT bitmaps: 代表組成目前這個 pack 的 NAT SIT blocks
- NAT and SIT journals: 包含一些些最近更新的 NAT SIT 的 entry,避免頻繁地更新 NAT SIT。
- Summary blocks of active segments: 由 memory 中 SSA blocks 組成,在未來會 flush 到 SSA area。
- orphan blocks: 紀錄 orphan inode 的資訊。 orphan inode (會發生在有兩個 process 同時使用同一個 file ,其中一個 process 刪除該檔案,則該檔案會被標記為 orphan block)。
![](https://i.imgur.com/hNxorLe.png)
![](https://i.imgur.com/bfIRXIn.png)
:::info
(不確定的解釋)
multi-level hashtable 感覺上有點像是 TST 但又不是,主要是藉由多層,每一層都會有對應得一個 block ,每一個 block 再往下去找。
但在 dentry 中並沒有提到如何處理 collision 的問題,也沒有提到說切割多大才算是好的切割方法。
:::
### Conclusion
目前主流的硬碟形式應該幾乎都是 SSD ,但既有的檔案系統設計對於 SSD 存取來說不是那麼友善。詳細的特徵可能要留到 Flash File System 解說。
### ref
1. wiki [link](https://zh.wikipedia.org/wiki/F2FS)
2. https://lwn.net/Articles/518718/
3. introduce to F2FS from samsung [link](https://www.linuxsecrets.com/elinux-wiki/images/1/12/Elc2013_Hwang.pdf)
4. original paper [link](https://www.usenix.org/conference/fast15/technical-sessions/presentation/lee)
5. http://linux.vbird.org/linux_basic/0230filesystem.php#harddisk
## Btrfs
由 oracle 在 2007 研發,預計是要替換掉 Linux 中 ext 系列的檔案系統。
一些基礎的設定:
- page, block: 4KB 連續空間。是通用的 size 在 Intel 架構上,在其他架構上可能可以更大,但就為了簡單來描述。
- Extent: 在 disk 上一塊連續的空間,對齊 page,所以長度為 page 的倍數。可以翻成"範圍",因為檔案系統通常是連續分配的,所以用這個可以大幅減少管理檔案空間的開銷。(在一般的 ext 3上,每增加一個 1GB 的檔案就需要 256K 大小的空間存放 block 去管理)
- Copy-on-Write(COW): COW 傳統上會將資料即時寫回原始位置,但這個 COW 是將資料新建一個版本寫在其他位置,否則斷電或是系統崩潰,原始的版本也會受到汙染。
(這p 用的基本上是 b-5 tree)
### Design
1. COW friendly B-trees: 使用 B-tree 但維持下列三個特性
- top-down update procedure
- remove leaf-chaining
- use lazy reference-counting for space management: 因為 COW 的關係,所以會讓整個 tree 變成 DAG (有向無環圖),因此用 ref-count 來記錄有多少個 pointer 指向自身 node。ref-counter 會額外放在 extent-tree,這樣更改的時候就不需要更改到 node 本身。
![](https://i.imgur.com/DHK3PuQ.png)
![](https://i.imgur.com/xUFvs0m.png)
![](https://i.imgur.com/rhG7CB2.png)
![](https://i.imgur.com/90Kf08N.png)
![](https://i.imgur.com/6ahsoti.png)
2. checkpoint:
3. BtrFS:
superblock 會在固定的 disk location,然後指向 root tree。
BtrFS 可以視為由 B-trees 組成的,解決了部分 ext 系列文件系統中的既有問題
- subvolume: subvolume 負責保存用戶可見的文件和目錄的訊息,同時該結構也是一個 b-tree。該結構可以達成 Snapshot (因為COW特性)。subvolume 達成了可以將整個 FS 切割成多個 subvolume ,再合起來變成一個 forest 來進行檔案系統的管理。
- Extent allocation tree:
![](https://i.imgur.com/nT6efGl.png)
:::info
Snapshot: 快照
假設對資料庫某一瞬間執行快照,可以保存該瞬間的檔案系統。
shadow:
Shadowing is a technique used by file systems like WAFL [D. Hitz et al. 1994] and
ZFS [V. Henson et al. 2003] to ensure atomic update to persistent data-structures.
It is a powerful mechanism that has been used to implement snapshots, crashrecovery, write-batching, and RAID. The basic scheme is to look at the file system
as a large tree made up of fixed-sized pages. Shadowing means that to update
an on-disk page, the entire page is read into memory, modified, and later written
to disk at an alternate location. When a page is shadowed its location on disk
changes, this creates a need to update (and shadow) the immediate ancestor of the
page with the new address. Shadowing propagates up to the file system root.
:::
###
### ref
[群暉系統的 btrfs](https://kknews.cc/zh-tw/news/jlzjl5y.html)
[synology introduction](https://www.synology.com/zh-tw/dsm/Btrfs)
[wiki](https://en.wikipedia.org/wiki/Btrfs)
[original paper](https://dl.acm.org/doi/abs/10.1145/2501620.2501623)
[shadowing and clone]()
[LWN.net The Btrfs FS](https://lwn.net/Articles/576276/)