關鍵詞:OverlayFS、Whiteout等等。
測試環境:Linux al-B250-HD3 4.15.0-99-generic #100~16.04.1-Ubuntu SMP Wed Apr 22 23:56:30 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
1. OverlayFS介紹
OverlayFS是一種堆疊文件系統,它依賴並建立在其它的文件系統智商,不直接參與磁盤空間結構的划分,僅將原來文件系統中不同目錄和文件進行“合並”。
因此OverlayFS更像是一個粘合劑,輸出多個文件系統目錄的“合集”。
1.1 OverlayFS應用
1.1.1 Overlay Driver
1.1.2 Overlay Driver2
2. OverlayFS分析
2.1 內核配置打開OverlayFS
File systems->Overlay filesystem support
2.2 OverlayFS架構分析
使能CONFIG_OVERLAY_FS之后,OverlayFS相關代碼如下:
fs/overlayfs/
├── copy_up.c
├── dir.c
├── inode.c
├── Kconfig
├── Makefile
├── overlayfs.h
├── readdir.c
└── super.c
相關幫助文件在Documentation/filesystems/overlayfs.txt。
3. OverlayFS掛載
掛載一個overlay文件系統,可以通過mount -t overlay -o <options> overlay <mount point>來實現。
<mount point>是最終overlay的掛載點。
其中overlay的options有如下:
- lowerdir=<dir>:指定用戶需要掛載的lower層目錄,lower層支持多個目錄,用“:”間隔,優先級依次降低。最多支持500層。
- upperdir=<dir>:指定用戶需要掛載的upper層目錄,upper層優先級高於所有的lower層目錄。
- workdir=<dir>:指定文件系統掛載后用於存放臨時和間接文件的工作基礎目錄。
- default_permissions:
- redirect_dir=on/off:開啟或關閉redirect directory特性,開啟后可支持merged目錄和純lower層目錄的rename/renameat系統調用。
- index=on/off:開啟或關閉index特性,開啟后可避免hardlink copyup broken問題。
下面將lower和upper進行overlay,掛載到merge目錄,臨時workdir為work目錄。
mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay merge
如下同樣將lower和upper進行overlay到merge,但是merge為只讀屬性。
mount -t overlay -o lowerdir=upper:lower overlay merge
4. OverlayFS使用
在使用如上mount進行OverlayFS合並之后,遵循如下規則:
- lowerdir和upperdir兩個目錄存在同名文件時,lowerdir的文件將會被隱藏,用戶只能看到upperdir的文件。
- lowerdir低優先級的同目錄同名文件將會被隱藏。
- 如果存在同名目錄,那么lowerdir和upperdir目錄中的內容將會合並。
- 當用戶修改mergedir中來自upperdir的數據時,數據將直接寫入upperdir中原來目錄中,刪除文件也同理。
- 當用戶修改mergedir中來自lowerdir的數據時,lowerdir中內容均不會發生任何改變。因為lowerdir是只讀的,用戶想修改來自lowerdir數據時,overlayfs會首先拷貝一份lowerdir中文件副本到upperdir中。后續修改或刪除將會在upperdir下的副本中進行,lowerdir中原文件將會被隱藏。
- 如果某一個目錄單純來自lowerdir或者lowerdir和upperdir合並,默認無法進行rename系統調用。但是可以通過mv重命名。如果要支持rename,需要CONFIG_OVERLAY_FS_REDIRECT_DIR。
4.1 構建測試用例
通過下面的腳本構建測試用例。
#!/bin/sh create() { mkdir -p lower/common-dir lower/lower-dir upper/common-dir upper/upper-dir merge work touch lower/common-dir/lower-file lower/lower-dir/lower-file upper/common-dir/upper-file upper/upper-dir/upper-file echo "From lower." > lower/common-file echo "From upper." > upper/common-file echo "From lower." > lower/lower-file echo "From upper." > upper/upper-file mount -t overlay -o lowerdir=lower,upperdir=upper,workdir=work overlay merge #mount -t overlay -o lowerdir=upper:lower overlay merge } delete() { umount merge rm -rf lower upper merge work } case $1 in create) create ;; delete) delete ;; esac
通過sudo ./overlayfs_test.sh create/delete創建測試環境或者清空。
如上的腳本構建的OverlayFS結果如下:兩者共同目錄common-dir內容進行了合並;重復文件common-file為uppderdir中的common-file。
目錄結構如下:
├── lower │ ├── common-dir │ │ └── lower-file │ ├── common-file │ ├── lower-dir │ │ └── lower-file │ └── lower-file ├── merge │ ├── common-dir │ │ ├── lower-file │ │ └── upper-file │ ├── common-file │ ├── lower-dir │ │ └── lower-file │ ├── lower-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file ├── overlayfs_test.sh ├── upper │ ├── common-dir │ │ └── upper-file │ ├── common-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file └── work └── work [error opening dir]
4.2 新增文件或目錄
分別在merge下創建new-dir、new-file、common-dir/new-file、lower-dir/new-file。
sudo mkdir merge/new-dir sudo touch merge/new-file merge/common-dir/new-file merge/lower-dir/new-file
查看結果如下:
. ├── lower │ ├── common-dir │ │ └── lower-file │ ├── common-file │ ├── lower-dir │ │ └── lower-file │ └── lower-file ├── merge │ ├── common-dir │ │ ├── lower-file │ │ ├── new-file │ │ └── upper-file │ ├── common-file │ ├── lower-dir │ │ ├── lower-file │ │ └── new-file │ ├── lower-file │ ├── new-dir │ ├── new-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file ├── overlayfs_test.sh ├── upper │ ├── common-dir │ │ ├── new-file │ │ └── upper-file │ ├── common-file │ ├── lower-dir │ │ └── new-file │ ├── new-dir │ ├── new-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file └── work └── work [error opening dir]
可以看出lower目錄沒有發生變化,在upper中新增lower-dir/new-file。其他所有的新增文件也都在upper中。
4.3 修改文件或目錄
修改common-dir/lower-file、common-dir/upper-file、lower-dir/lower-file、upper-dir/upper-file、重命名lower-dir為new-dir。
vi將內容改成"new": merge/common-dir/upper-file merge/common-dir/lower-file merge/lower-dir/lower-file merge/upper-dir/upper-file merge/common-file sudo mv merge/lower-dir merge/new-dir
結果如下:
. ├── lower │ ├── common-dir │ │ └── lower-file │ ├── common-file │ ├── lower-dir │ │ └── lower-file │ └── lower-file ├── merge │ ├── common-dir │ │ ├── lower-file │ │ └── upper-file │ ├── common-file │ ├── lower-file │ ├── new-dir │ │ └── lower-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file ├── overlayfs_test.sh ├── upper │ ├── common-dir │ │ ├── lower-file │ │ └── upper-file │ ├── common-file │ ├── lower-dir │ ├── new-dir │ │ └── lower-file │ ├── upper-dir │ │ └── upper-file │ └── upper-file └── work └── work [error opening dir]
同樣lower中文件沒有發生修改,所有修改都在upper中產生。
其中修改了upper/common-dir/upper-file、common-file、upper-dir/upper-file,新增了common-dir/lower-file、new-dir/lower-file、lower-dir。
其中new-dir/lower-file是由lower-dir/lower-file文件件重命名而來的,新增lower-dir是一個特殊文件。
c--------- 1 root root 0, 0 6月 8 14:17 upper/lower-dir
Overlayfs針對這種場景設計了一套“障眼法”——Whiteout文件。Whiteout文件在用戶刪除文件時創建,用於屏蔽底層的同名文件,同時該文件在merge中是不可見的,所以用戶就看不到被刪除的文件或目錄了。
whiteout文件並非普通文件,而是主次設備號都為0的字符設備(可以通過"mknod <name> c 0 0"命令手動創建),當用戶在merge中通過ls命令(將通過readddir系統調用)檢查父目錄的目錄項時,overlayfs會自動過過濾掉和whiteout文件自身以及和它同名的lower層文件和目錄,達到了隱藏文件的目的,讓用戶以為文件已經被刪除了。
4.4 刪除文件或目錄
刪除所有merge中的目錄和文件。
sudo rm -rf merge/*
結果如下:
. ├── lower │ ├── common-dir │ │ └── lower-file │ ├── common-file │ ├── lower-dir │ │ └── lower-file │ └── lower-file ├── merge ├── overlayfs_test.sh ├── upper │ ├── common-dir │ ├── common-file │ ├── lower-dir │ └── lower-file └── work └── work [error opening dir]
可以看出所有upper中的目錄和文件被刪除了,所有lower中目錄和文件都有對應的whiteout對應文件。
參考文檔:《深入理解overlayfs(一):初識》、《深入理解overlayfs(二):使用與原理分析》、《OverlayFS》、《DOCKER存儲驅動之OVERLAYFS簡介》。