测试环境: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 overlay 来实现。
是最终overlay的挂载点。
其中overlay的options有如下:
lowerdir=
:指定用户需要挂载的lower层目录,lower层支持多个目录,用“:”间隔,优先级依次降低。最多支持500层。
upperdir=
:指定用户需要挂载的upper层目录,upper层优先级高于所有的lower层目录。
workdir=
:指定文件系统挂载后用于存放临时和间接文件的工作基础目录。
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。
12 |
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 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对应文件。
原作者:DMCF