overlay文件系统的主要目的是要实现文件系统重叠,docker中的差分机制所依赖的文件系统分层就是依赖这种技术来实现的

1. upper and lower

overlay机制允许将两个文件系统重叠成一个文件系统,其中一个是upper,另一个是lower,对用户的可视顺序是:
upper -> lower

简单来说,如果upper和lower同时存在一个相同的文件,那么用户看到的是upper中的文件,lower中的同路径文件会被自动隐藏

overlay只关心文件,目录是会被穿透的,所以严格来说,overlay重叠的是目录树,而不是“文件系统”

所有的修改都会写入upper,lower是只读的。upper的文件系统必须支持trusted.*扩展属性,所以upper是不支持NFS的

2. 用法

mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,workdir=/work /merged

如果不写upper和workdir,就是只读挂载
mount -t overlay overlay -olowerdir=/lower /merged

3. 写目录操作

目录的写操作有三种:新增 -> 删除

所有新增操作都是在upper进行的,因为只有upper可写,lower是只读的

删除操作比较复杂,有两种情况:一种是删除的目录在upper中而不在lower中,一种是删除的目录在lower中但是不在upper中,另一种是既在upper也在lower中

第一种情况:只在upper中,不在lower中
这种情况下,直接删除upper中的目录即可

第二、三种情况,是类似的,主 要是overlay需要在upper中如何表达lower中的目录被删除这个信息。我们知道overlay在重叠的时候目录会被穿透,如果只删除 upper中的目录,那么下次merge的时候,仍然能看到lower中的目录,显然这是不符合需求的。upper中的删除操作应该能够被持久化,下次 merge的时候,能够自动忽略lower中的同名目录

有两种解决方案:

1). 特殊的设备文件

overlay通过一个特殊的字符设备来解决目录被删除的问题,如果一个lower中的目录被删除,这个目录在upper中会被转变成一个特殊的字符设备文件:
mknod ${deleted_dir} c 0 0

overlay重叠目录树的时候,如果发现upper中某个文件是一个特殊的字符设备:major:minor都是0,则会忽略lower中的同名目录

2). 文件系统xattr属性

通过设置文件的trusted.overlay.opaque=y属性来表示当前目录是一个透明目录,这类文件对应的lower中的目录在重叠时会被忽略

4. 读目录操作

目 录被访问时,overlayfs会先读取upper中的目录,再读取lower中的目录,然后做合并,合并的结果火保存在dentry cache里。不同的进程同时访问同一个目录,会有不同的cache【很有可能这个cache是进程级别的,并保存在struct task结构里】

读操作不会影响upper中的目录树结构

另外目录seek的问题【和overlay的实现有关】:
seek offsets are assigned sequentially when the directories are read. Thus if
  - read part of a directory
  - remember an offset, and close the directory
  - re-open the directory some time later
  - seek to the remembered offset

there may be little correlation between the old and new locations in the list of filenames, particularly if anything has changed in the directory.

5. 文件

文件的新增操作很简单:直接存储在upper文件系统中即可

删除操作稍微复杂,原理和实现方式和目录被删除是一致的

修改类似于copy-on-write,如果是upper中的文件被修改,则直接修改upper文件系统中的文件,如果是lower中的文件被修改,则会首先copy到upper,然后在upper中修改

copy过程中会创建必要的目录信息

6. Non-standard behavior

使用overlay的过程中有很多地方需要注意,overlay的实现机制和一些用户态程序的行为可能不兼容,例如:
1. overlay的copy-on-write机制,会导致文件的inode发生变化。虽然copy的时候,会使用完全一致的文件系统meta信息,但是inode是不可能做到一致的,毕竟upper和lower在定义上是两个完全不同的文件系统

2. On a file opened with O_RDONLY fchmod(2), fchown(2), futimesat(2) and fsetxattr(2) will fail with EROFS.  
实际测试没有发现这个问题,可能新版本内核已经修复【待确认内核版本号】

3. hard link问题
当 lower中多个dentry同时指向同一个inode的时候,例如硬连,如果修改其中一个文件,copy-on-write机制会将这个文件copy到 upper再进行修改,这样的话修改之后的文件是个新文件,而原来的文件的其他dentry所指向的inode内容并没有修改

4. 原子性
overlayfs 的copy-on-write不是原子性的,可能会造成文件系统数据不一致。例如,copy-on-write过程中,upper的文件刚被创建,但是 meta信息以及其他overlay属性未设置正确,则会导致upploer和lower重叠时出现非预期行为

overlayfs文件系统数据在机器宕机、源文件系统损坏、磁盘故障等情况下都是不可靠的

Leave a Comment