# 了解 Btrfs Filesystem 運作
## What is Copy-on-Write (CoW) and How does it work?
* Btrfs 檔案系統的所有寫入操作都會使用「Copy on Write(CoW)的機制」
* 如果你只是寫入一個之前不存在的檔案,那麼資料就會被寫入到空的空間中,並且組成檔案系統的一些 metadata blocks 會被「CoWed」(寫時複製)。
* 在「一般」的檔案系統中,如果你回頭覆蓋該檔案的一部分,那麼你正在寫入的那部分會直接覆蓋掉它所替換的資料。
* 在「CoW」檔案系統中,新的資料會被寫入到磁碟上的一個空閒空間,然後才會將檔案的 metadata 更改為指向新的資料。在那個時候,被替換的舊資料可以被釋放,因為沒有任何東西再指向它了。

## 實作 Copy-on-Write
1. Create a Btrfs filesystem on a single drive
```
~> mkfs.btrfs /dev/sdb
btrfs-progs v5.14
See http://btrfs.wiki.kernel.org for more information.
Label: (null)
UUID: b2a83758-9bfd-4e48-b079-a988f4cc7cbe
Node size: 16384
Sector size: 4096
Filesystem size: 50.00GiB
Block group profiles:
Data: single 8.00MiB
Metadata: DUP 256.00MiB
System: DUP 8.00MiB
SSD detected: no
Zoned device: no
Incompat features: extref, skinny-metadata
Runtime features:
Checksum: crc32c
Number of devices: 1
Devices:
ID SIZE PATH
1 50.00GiB /dev/sdb
```
2. 將一個 sdb 這顆硬碟 mount 到 /mnt/pool1 目錄上
```
$ mkdir /mnt/pool1
$ mount -t btrfs /dev/sdb /mnt/pool1
$ df -h | egrep "Filesystem|pool1"
Filesystem Size Used Avail Use% Mounted on
/dev/sdb 50G 3.5M 50G 1% /mnt/pool1
```
```
# 檢視根目錄之檔案系統類型
~> df -hT /
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/system-root btrfs 32G 2.4G 30G 8% /
# 建立並切換工作目錄
~> mkdir cow/ && cd cow
# 產生 1 G 大小之檔案
~> fallocate -l 1G one
# 使用 copy on write 的方式複製檔案
~> cp --reflink=always one two
# 不使用 copy on write 複製檔案
~> cp --reflink=never one three
# 顯示 btrfs 檔案系統中當前目錄下每個檔案的硬碟使用量
~> btrfs filesystem du .
Total Exclusive Set shared Filename
1.00GiB 0.00B - ./one
1.00GiB 0.00B - ./two
991.38MiB 991.38MiB - ./three
2.97GiB 991.38MiB 1.00GiB .
# 檢視 one、two 和 three 三個檔案 在 儲存裝置上的絕對位置
# one、two 的 block 資料區間是相同的,three 是自己的 block 資料區間
~> filefrag -v one two three
Filesystem type is: 9123683e
File size of one is 1073741824 (262144 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 65535: 7972394.. 8037929: 65536: unwritten,shared
1: 65536.. 262143: 8120119.. 8316726: 196608: 8037930: last,unwritten,shared,eof
one: 2 extents found
File size of two is 1073741824 (262144 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 65535: 7972394.. 8037929: 65536: unwritten,shared
1: 65536.. 262143: 8120119.. 8316726: 196608: 8037930: last,unwritten,shared,eof
two: 2 extents found
File size of three is 1073741824 (262144 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 32767: 8037930.. 8070697: 32768:
1: 32768.. 65535: 8316727.. 8349494: 32768: 8070698:
2: 65536.. 262143: 8371456.. 8568063: 196608: 8349495: last,eof
three: 3 extents found
```
* 修改 two 檔案的內容
* 原本舊的 block 資料區間就被釋放掉了,已經寫入到新的 block 資料區間
```
# echo "abc" > /root/cow/two
# filefrag -v /root/cow/one /root/cow/two
Filesystem type is: 9123683e
File size of /root/cow/one is 1073741824 (262144 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 65535: 2831685.. 2897220: 65536: unwritten
1: 65536.. 262143: 2899200.. 3095807: 196608: 2897221: last,unwritten,eof
/root/cow/one: 2 extents found
File size of /root/cow/two is 4 (1 block of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 4095: 0.. 4095: 4096: last,not_aligned,inline,eof
/root/cow/two: 1 extent found
```
## what is subvolume
* 在 Btrfs 文件系統中,subvolume 是一種用於將文件系統劃分為邏輯分區的功能。子卷就像獨立的文件系統一樣,它們具有自己的文件和目錄樹,並且可以獨立地掛載、備份和管理。
* subvolume 具有彈性,可以在檔案系統的任何位置建立,也可以建立在其他 subvolume 之內。由於它們的階層性質,包含其他子 subvolume 的 subvolume 在刪除前無法被刪除。
* 每個 Btrfs 的實作都會包含一個父/主 subvolume 。這是預設掛載的最上層 subvolume 。對於使用者來說, subvolume 看起來就像是目錄和子目錄。
## 實作 Btrfs Subvolume Snapshot 備份與還原
```
# 建立 subvolume ,命名為 demo
~> sudo btrfs sub create /root/demo/
Create subvolume '/root/demo’
# 檢查 subvolume 是否建立
~> sudo btrfs sub list -o /root
ID 325 gen 781 top level 262 path @/root/demo
# Subvolume appear as directory in the file system
~> sudo ls -ld /root/demo
drwxr-xr-x 1 root root 0 Jun 9 22:03 /root/demo
# 產生 20 G 的檔案
~> sudo fallocate -l 20G /root/demo/demo.txt
```
```
# 查看檔案大小
~> sudo btrfs filesystem du -s /root/demo/demo.txt
Total Exclusive Set shared Filename
20.00GiB 20.00GiB 0.00B /root/demo/demo.txt
# 建立 Subvolume Snapshot
~> sudo btrfs subvolume snapshot -r "/root/demo/" "/root/demo-snap/"
Create a readonly snapshot of '/root/demo/' in '/root/demo-snap’
# 查看 Subvolume Snapshot 是否建立成功
~> sudo btrfs subvolume list -o /root/
ID 325 gen 822 top level 262 path @/root/demo
ID 346 gen 822 top level 262 path @/root/demo-snap
# 檢查快照檔案是否符合預期
~> sudo ls -lh /root/demo-snap/
total 20G
-rw-r--r-- 1 root root 20G Jun 10 04:17 demo.txt
```
```
#檢視原始檔案和快照後備份後之檔案在儲存裝置上的絕對位置
~> sudo filefrag -v /root/demo/demo.txt /root/demo-snap/demo.txt
Filesystem type is: 9123683e
File size of /root/demo/demo.txt is 21474836480 (5242880 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 131071: 684781.. 815852: 131072: unwritten,shared
1: 131072.. 5242879: 859392.. 5971199: 5111808: 815853: last,unwritten,shared,eof
/root/demo/demo.txt: 2 extents found
Filesystem type is: 9123683e
File size of /root/demo-snap/demo.txt is 21474836480 (5242880 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 131071: 684781.. 815852: 131072: unwritten,shared
1: 131072.. 5242879: 859392.. 5971199: 5111808: 815853: last,unwritten,shared,eof
/root/demo-snap/demo.txt: 2 extents found
```
```
#檢視原始檔案和快照後備份後之檔案大小資訊
~> sudo btrfs filesystem du -s /root/demo/demo.txt /root/demo-snap/demo.txt
Total Exclusive Set shared Filename
20.00GiB 0.00B 20.00GiB /root/demo/demo.txt
20.00GiB 0.00B 20.00GiB /root/demo-snap/demo.txt
# 檢視以上兩個檔案總共占用多少硬體空間
~> sudo df -hT /root
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/system-root btrfs 32G 23G 9.3G 71% /root
```
* 破壞和還原檔案
```
# 嘗試直接刪除 read-only 之 subvolume snapshot
~> sudo rm -r /root/demo-snap
rm: cannot remove '/root/demo-snap/demo.txt': Read-only file system
# 直接刪除在 demo 目錄下的原始檔案
~> sudo rm /root/demo/demo.txt
# 透過快照備份檔還原原始檔
~> sudo cp --reflink=always /root/demo-snap/demo.txt /root/demo/
# 檢視檔案是否恢復
~> sudo ls -lh /root/demo/
total 20G
-rw-r--r-- 1 root root 20G Jun 10 08:40 demo.txt
```
* 清除 subvolume
```
# sudo btrfs subvolume delete /root/demo-snap
Delete subvolume (no-commit): '/root/demo-snap'
# sudo btrfs subvolume delete /root/demo/
Delete subvolume (no-commit): '/root/demo'
## 確認空間已被釋放
# sudo df -hT /root
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/system-root btrfs 32G 3G 29.3G 9.3% /root
```