對於大部分文件系統來講,在磁盤上建立好文件系統,而後再掛載到系統中去就完事了。但對於Btrfs來講,除了在格式化和掛載的時候指定不一樣的參數外,還支持不少其餘的功能,好比管理多塊硬盤,支持LVM和RAID等,具體的能夠參考它的官方文檔或者Linux下常見文件系統對比php
Btrfs是Linux下你們公認的將會替代ext4的下一代文件系統,功能很是強大。本篇不會介紹Btrfs的原理,也不會介紹Btrfs的全部功能,只是挑了其中的subvolume和snapshot這兩個特性來進行介紹linux
本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過git
先建立一個虛擬的硬盤,而後將它格式化成Btrfs,最後將它掛載到目錄/mnt/btrfsubuntu
#爲了簡單起見,這裏只使用一塊硬盤來作測試(Btrfs能夠管理多塊硬盤或分區)。 #新建一個文件,用來虛擬一塊硬盤 dev@ubuntu:~$ fallocate -l 512M /tmp/btrfs.img #在上面建立Btrfs文件系統 dev@ubuntu:~$ mkfs.btrfs /tmp/btrfs.img btrfs-progs v4.4 See http://btrfs.wiki.kernel.org for more information. Label: (null) UUID: fd5efcd3-adc2-406b-a684-e6c87dde99a1 Node size: 16384 Sector size: 4096 Filesystem size: 512.00MiB Block group profiles: Data: single 8.00MiB Metadata: DUP 40.00MiB System: DUP 12.00MiB SSD detected: no Incompat features: extref, skinny-metadata Number of devices: 1 Devices: ID SIZE PATH 1 512.00MiB /tmp/btrfs.img #建立文件夾並掛載 dev@ubuntu:~$ sudo mkdir /mnt/btrfs dev@ubuntu:~$ sudo mount /tmp/btrfs.img /mnt/btrfs #修改權限,這樣後面的部分操做就再也不須要sudo dev@ubuntu:~$ sudo chmod 777 /mnt/btrfs
能夠把subvolume理解爲一個虛擬的設備,由Btrfs管理,建立好了以後就自動掛載到了Btrfs文件系統的一個目錄上,因此咱們在文件系統裏面看到的subvolume就是一個目錄,但它是一個特殊的目錄,具備掛載點的一些屬性。segmentfault
新建立的Btrfs文件系統會建立一個路徑爲「/」的默認subvolume,即root subvolume,其ID爲5(別名爲0),這是一個ID和目錄都預設好的subvolume。bash
#這裏從mount的參數「subvolid=5,subvol=/」就能夠看出來, #默認的root subvolume的id爲5,路徑爲「/」 dev@debian:/mnt/btrfs$ mount|grep btrfs /dev/loop1 on /mnt/btrfs type btrfs (rw,relatime,space_cache,subvolid=5,subvol=/)
這裏咱們將會利用Btrfs提供的工具建立兩個新subvolume和兩個文件夾,來看看他們之間的差異工具
dev@ubuntu:~$ cd /mnt/btrfs #btrfs命令是Btrfs提供的應用層工具,能夠用來管理Btrfs #這裏依次建立兩個subvolume,建立完成以後會自動在當前目錄下生成兩個目錄 dev@ubuntu:/mnt/btrfs$ btrfs subvolume create sub1 Create subvolume './sub1' dev@ubuntu:/mnt/btrfs$ btrfs subvolume create sub2 Create subvolume './sub2' #建立兩個文件夾 dev@ubuntu:/mnt/btrfs$ mkdir dir1 dir2 #在sub一、sub2和dir1中分別建立一個文件 dev@ubuntu:/mnt/btrfs$ touch dir1/dir1-01.txt dev@ubuntu:/mnt/btrfs$ touch sub1/sub1-01.txt dev@ubuntu:/mnt/btrfs$ touch sub2/sub2-01.txt #最後看看目錄結構,是否是看起來sub1和dir1沒什麼區別? dev@ubuntu:/mnt/btrfs$ tree . ├── dir1 │ └── dir1-01.txt ├── dir2 ├── sub1 │ └── sub1-01.txt └── sub2 └── sub2-01.txt
不過因爲每一個subvolume都是一個單獨的虛擬設備,因此沒法跨subvolume創建硬連接oop
#雖然sub1和sub2屬於相同的Btrfs文件系統,而且在一塊物理硬盤上 #但因爲他們屬於不一樣的subvolume,因此在它們之間創建硬連接失敗 dev@ubuntu:/mnt/btrfs$ ln ./sub1/sub1-01.txt ./sub2/ ln: failed to create hard link './sub2/sub1-01.txt' => './sub1/sub1-01.txt': Invalid cross-device link
subvolume不能用rm來刪除,只能經過btrfs命令來刪除測試
#普通的目錄經過rm就能夠被刪除 dev@ubuntu:/mnt/btrfs$ rm -r dir2 #經過rm命令刪除subvolume失敗 dev@ubuntu:/mnt/btrfs$ sudo rm -r sub2 rm: cannot remove 'sub2': Operation not permitted #須要經過btrfs命令才能刪除 #刪除sub2成功(就算subvolume裏面有文件也能被刪除) dev@ubuntu:/mnt/btrfs$ sudo btrfs subvolume del sub2 Delete subvolume (no-commit): '/mnt/btrfs/sub2' dev@ubuntu:/mnt/btrfs$ tree . ├── dir1 │ └── dir1-01.txt └── sub1 └── sub1-01.txt
上面刪除的時候能夠看到這樣的提示: Delete subvolume (no-commit),表示subvolume被刪除了,但沒有提交,意思是在內存裏面生效了,但磁盤上的內容還沒刪,意味着若是這個時候系統crash掉,這個subvolume有可能還會回來。btrfs這樣作的好處是刪除速度很快,不會影響使用,缺點是有可能在後臺commit的過程當中系統掛掉,致使commit失敗。spa
爲了確保subvolume裏的數據被真正的從磁盤上移除掉,能夠在刪除subvolume的時候指定-c參數,這樣btrfs命令會等提交完成以後再返回
dev@ubuntu:/mnt/btrfs$ sudo btrfs subvolume del -c sub2 Delete subvolume (commit): '/mnt/btrfs/sub2'
subvolume能夠直接經過mount命令掛載,和掛載其它設備沒什麼區別,具體的掛載參數請參考文檔
#建立一個用於掛載點的目錄 dev@ubuntu:/mnt/btrfs$ sudo mkdir /mnt/sub1 #先查看待掛載的subvolume的id dev@debian:/mnt/btrfs$ sudo btrfs subvolume list /mnt/btrfs/ ID 256 gen 9 top level 5 path sub1 #經過-o參數來指定要掛載的subvolume的ID #經過路徑來掛載也是同樣的效果:sudo mount -o subvol=/sub1 /tmp/btrfs.img /mnt/sub1/ dev@debian:/mnt/btrfs$ sudo mount -o subvolid=256 /tmp/btrfs.img /mnt/sub1/ dev@debian:/mnt/btrfs$ tree /mnt/sub1/ /mnt/sub1/ └── sub1-01.txt
subvolume能夠被設置成只讀狀態
#經過btrfs property能夠查看和修改subvolume的只讀狀態 #默認狀況下,subvolume的只讀屬性爲false,即容許寫 dev@ubuntu:/mnt/btrfs$ btrfs property get -ts ./sub1/ ro=false #將sub1的只讀屬性設置成true dev@ubuntu:/mnt/btrfs$ btrfs property set -ts ./sub1/ ro true dev@ubuntu:/mnt/btrfs$ btrfs property get -ts ./sub1 ro=true #寫文件失敗,提示文件系統只讀 dev@ubuntu:/mnt/btrfs$ touch ./sub1/sub1-02.txt touch: cannot touch './sub1/sub1-02.txt': Read-only file system #將sub1的狀態改回去,以避免影響後續測試 dev@ubuntu:/mnt/btrfs$ btrfs property set -ts ./sub1/ ro false
能夠在subvolume的基礎上製做快照,幾點須要注意:
默認狀況下subvolume的快照是可寫的
快照是特殊的subvolume,具備subvolume的屬性。因此快照也能夠經過mount掛載,也能夠經過btrfs property命令設置只讀屬性
因爲快照的本質就是一個subvolume,因此能夠在快照上面再作快照
在subvolume上作了快照後,subvolume和快照就會共享全部的文件,只有當文件更新的時候,纔會觸發COW(copy on write),因此建立快照很快,基本不花時間,而且Btrfs的COW機制很高效,就算多個快照共享一個文件,更新這個文件也和更新一個普通文件差很少的速度。
若是用過git的話,就能很容易理解Btrfs裏的快照,能夠把subvolume理解爲git裏面的master分支,而快照就是從master checkout出來的新分支,因而快照跟git裏的分支有相似的特色:
建立快照幾乎沒有開銷
能夠在快照的基礎上再建立快照
當前快照裏面的修改不會影響其它快照
快照能夠被刪除
固然subvolume也能夠像git裏的master同樣被刪除。
#在root subvolume的基礎上建立一個快照 #默認狀況下快照是可寫的,若是要建立只讀快照,須要加上-r參數 dev@debian:/mnt/btrfs$ sudo btrfs subvolume snapshot ./ ./snap-root Create a snapshot of './' in './snap-root' #建立完成後,能夠看到咱們已經有了兩個subvolume dev@debian:/mnt/btrfs$ sudo btrfs subvolume list ./ ID 256 gen 11 top level 5 path sub1 ID 257 gen 13 top level 5 path snap-root #咱們能夠經過指定-s參數來只列出快照 dev@debian:/mnt/btrfs$ sudo btrfs subvolume list -s ./ ID 257 gen 10 cgen 10 top level 5 otime 2017-03-05 21:46:03 path snap-root #再來看看快照snap-root中的文件,能夠看到有dir1及下面的文件, #但看不到sub1下的文件,那是由於sub1是一個subvolume, #在作一個subvolume的快照的時候,不會將它裏面的subvolume也作快照 dev@debian:/mnt/btrfs$ tree ./snap-root ./snap-root ├── dir1 │ └── dir1-01.txt └── sub1 #建立sub1的一個快照,能夠看到sub1裏面的文件出如今了快照裏面 dev@debian:/mnt/btrfs$ sudo btrfs subvolume snapshot ./sub1/ ./snap-sub1 Create a snapshot of './sub1/' in './snap-sub1' #而後在sub1和它的快照snap-sub1下面各自建立一個文件, #會發現它們之間不受影響 dev@debian:/mnt/btrfs$ touch snap-sub1/snap-sub1-01.txt dev@debian:/mnt/btrfs$ touch sub1/sub1-02.txt dev@debian:/mnt/btrfs$ tree . ├── dir1 │ └── dir1-01.txt ├── snap-root │ ├── dir1 │ │ └── dir1-01.txt │ └── sub1 ├── snap-sub1 │ ├── snap-sub1-01.txt │ └── sub1-01.txt └── sub1 ├── sub1-01.txt └── sub1-02.txt
刪除快照和刪除subvolume是同樣的,沒有區別
dev@debian:/mnt/btrfs$ sudo btrfs subvolume del snap-root Delete subvolume (no-commit): '/mnt/btrfs/snap-root' dev@debian:/mnt/btrfs$ sudo btrfs subvolume del snap-sub1 Delete subvolume (no-commit): '/mnt/btrfs/snap-sub1' dev@debian:/mnt/btrfs$ tree . ├── dir1 │ └── dir1-01.txt └── sub1 ├── sub1-01.txt └── sub1-02.txt
能夠設置Btrfs分區的默認subvolume,即在掛載磁盤的時候,能夠只讓分區中的指定subvolume對用戶可見。看下面的例子:
#查看sub1的ID dev@debian:/mnt/btrfs$ sudo btrfs subvolume list ./ ID 256 gen 14 top level 5 path sub1 #將sub1設置爲當前Btrfs文件系統的默認subvolume dev@debian:/mnt/btrfs$ sudo btrfs subvolume set-default 256 /mnt/btrfs/ #從新將虛擬硬盤掛載到一個新目錄 dev@debian:/mnt/btrfs$ sudo mkdir /mnt/btrfs1 dev@debian:/mnt/btrfs$ sudo mount /tmp/btrfs.img /mnt/btrfs1/ #這裏將只能看到sub1下的文件 dev@debian:/mnt/btrfs$ tree /mnt/btrfs1 /mnt/btrfs1 ├── sub1-01.txt └── sub1-02.txt #因爲Btrfs原來的默認subvolume是root subvolume, #其ID是5(也能夠經過0來標識), #因此咱們能夠經過一樣的命令將默認subvolume再改回去 dev@debian:/mnt/btrfs$ sudo btrfs subvolume set-default 0 /mnt/btrfs/
利用snapshot和default subvolume,能夠很方便的實現不一樣系統版本的切換,好比將系統安裝在一個subvolume下面,當要作什麼危險操做的時候,先在subvolume的基礎上作一個快照A,若是操做成功,那麼什麼都不用作(或者把A刪掉),繼續用原來的subvolume,A不被刪掉也不要緊,多一個快照在那裏也不佔空間,若是操做失敗,那麼能夠將A設置成default subvolume,並將原來的subvolume刪除,這樣就至關於系統回滾。
有了這樣的功能後,Linux的每次操做都能回滾,養成在修改操做前作snapshot的習慣,就不再用擔憂rm誤刪文件了。
如今有些發行版已經有了相似的功能,如ubuntu,將安裝工具(apt)和Btrfs結合,自動的在安裝軟件以前打一個snapshot,而後安裝軟件,若是成功,刪除新的snapshot,若是失敗,修改default subvolume爲新的snapshot,刪除掉原來的snapshot,這樣對系統沒有任何影響,而且全部操做對用戶是透明的。
隨着Btrfs的成熟和普及,相信會改變一些咱們使用Linux的習慣。
Btrfs的功能太多,須要在使用的過程當中去熟悉,本文只是粗略的介紹了一下subvolume和snapshot,關於subvolume的增量備份和磁盤限額都沒有涉及到,下次有時間再繼續這部份內容。