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