作者:Neil Brown 请查看 MAINTAINERS 文件,了解将问题发送到何处。
Overlay 文件系统¶
本文档描述了在 Linux 中提供 overlay 文件系统功能(有时称为联合文件系统)的新方法的原型。overlay 文件系统尝试呈现一个文件系统,该文件系统是将一个文件系统覆盖在另一个文件系统之上的结果。
Overlay 对象¶
overlay 文件系统方法是“混合的”,因为出现在文件系统中的对象并不总是看起来属于该文件系统。在许多情况下,在联合体中访问的对象与访问原始文件系统中的相应对象没有区别。这从 stat(2) 返回的“st_dev”字段中最明显。
虽然目录将报告来自 overlay 文件系统的 st_dev,但非目录对象可能会报告来自提供该对象的较低文件系统或较高文件系统的 st_dev。类似地,只有与 st_dev 组合时,st_ino 才是唯一的,并且这两者都可能在非目录对象的生命周期内发生变化。许多应用程序和工具会忽略这些值,因此不会受到影响。
在所有 overlay 层都位于同一底层文件系统的特殊情况下,所有对象都将报告来自 overlay 文件系统的 st_dev 以及来自底层文件系统的 st_ino。这将使 overlay 挂载更符合文件系统扫描程序,并且 overlay 对象将与原始文件系统中的相应对象区分开来。
在 64 位系统上,即使所有 overlay 层都不在同一底层文件系统上,也可以通过“xino”功能实现相同的兼容行为。“xino”功能从真实对象的 st_ino 和底层 fsid 编号组成唯一的对象标识符。“xino”功能使用高 inode 号位作为 fsid,因为底层文件系统很少使用高 inode 号位。如果底层的 inode 号溢出到高 xino 位,overlay 文件系统将回退到该 inode 的非 xino 行为。
可以使用“-o xino=on”overlay 挂载选项启用“xino”功能。如果所有底层文件系统都支持 NFS 文件句柄,则 overlay 文件系统对象的 st_ino 值不仅是唯一的,而且在文件系统的生命周期内也是持久的。“-o xino=auto”overlay 挂载选项仅在满足持久 st_ino 要求时才启用“xino”功能。
下表总结了在不同的 overlay 配置中可以预期的结果。
Inode 属性¶
配置 |
持久 st_ino |
统一 st_dev |
st_ino == d_ino |
d_ino == i_ino [*] |
||||
---|---|---|---|---|---|---|---|---|
目录 |
!目录 |
目录 |
!目录 |
目录 |
!目录 |
目录 |
!目录 |
|
同一文件系统上的所有层 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
层不在同一文件系统上,xino=off |
否 |
否 |
是 |
否 |
否 |
是 |
否 |
是 |
xino=on/auto |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
是 |
xino=on/auto, ino 溢出 |
否 |
否 |
是 |
否 |
否 |
是 |
否 |
是 |
[*] nfsd v3 readdirplus 验证 d_ino == i_ino。 i_ino 通过几个 /proc 文件公开,例如 /proc/locks 和 /proc/self/fdinfo/<fd>(inotify 文件描述符)。
上层和下层¶
overlay 文件系统组合了两个文件系统 - 一个“上层”文件系统和一个“下层”文件系统。当名称在两个文件系统中都存在时,“上层”文件系统中的对象是可见的,而“下层”文件系统中的对象要么被隐藏,要么在目录的情况下,与“上层”对象合并。
将上层和下层称为“目录树”而不是“文件系统”更为正确,因为两个目录树很可能位于同一文件系统中,并且没有要求为上层或下层提供文件系统的根目录。
Linux 支持的各种文件系统都可以作为下层文件系统,但并非所有 Linux 可挂载的文件系统都具有 OverlayFS 工作所需的功能。下层文件系统不需要是可写的。下层文件系统甚至可以是另一个 overlayfs。上层文件系统通常是可写的,如果是这样,则必须支持创建 trusted.* 和/或 user.* 扩展属性,并且必须在 readdir 响应中提供有效的 d_type,因此 NFS 不适用。
两个只读文件系统的只读 overlay 可以使用任何文件系统类型。
目录¶
overlay 主要涉及目录。如果给定名称同时出现在上层和下层文件系统中,并且在其中任何一个中都指向非目录,则会隐藏下层对象 - 该名称仅指向上层对象。
如果上层和下层对象都是目录,则会形成一个合并的目录。
在挂载时,作为挂载选项“lowerdir”和“upperdir”给出的两个目录将组合成一个合并的目录
mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\
workdir=/work /merged
“workdir”需要是与 upperdir 位于同一文件系统上的空目录。
然后,每当在此类合并的目录中请求查找时,都会在每个实际目录中执行查找,并将组合结果缓存在属于 overlay 文件系统的 dentry 中。如果两个实际查找都找到目录,则两个目录都会存储,并创建一个合并的目录,否则只存储一个目录:如果存在则存储上层目录,否则存储下层目录。
仅合并目录中的名称列表。其他内容(例如元数据和扩展属性)仅针对上层目录报告。下层目录的这些属性将被隐藏。
白化和不透明目录¶
为了在不更改下层文件系统的情况下支持 rm 和 rmdir,overlay 文件系统需要在上层文件系统中记录已删除的文件。这是使用白化和不透明目录完成的(非目录始终是不透明的)。
白化创建为设备号为 0/0 的字符设备或具有 xattr“trusted.overlay.whiteout”的零大小常规文件。
当在合并目录的上层中找到白化时,将忽略下层中的任何匹配名称,并且白化本身也会被隐藏。
通过将 xattr“trusted.overlay.opaque”设置为“y”来使目录不透明。如果上层文件系统包含不透明目录,则会忽略下层文件系统中具有相同名称的任何目录。
不透明目录不应包含任何白化,因为它们没有任何用途。包含具有 xattr“trusted.overlay.whiteout”的常规文件的合并目录,还应通过在合并目录本身上将 xattr“trusted.overlay.opaque”设置为“x”来标记。这是为了避免在常见情况下在 readdir 期间检查所有条目的“trusted.overlay.whiteout”的开销。
readdir¶
当在合并的目录上发出“readdir”请求时,会读取上层和下层目录,并以显而易见的方式合并名称列表(首先读取上层,然后读取下层 - 不会重新添加已存在的条目)。此合并的名称列表缓存在“struct file
”中,只要文件保持打开状态,该列表就会保留。如果目录由两个进程同时打开和读取,则它们将各自拥有单独的缓存。seekdir 到目录的开头(偏移量 0)后跟 readdir 将导致缓存被丢弃并重建。
这意味着在读取目录时,合并目录的更改不会显示。许多程序不太可能注意到这一点。
当读取目录时,按顺序分配 seek 偏移量。因此,如果
读取目录的一部分
记住偏移量并关闭目录
稍后重新打开目录
跳转到记住的偏移量
文件名列表中的旧位置和新位置之间可能没有多少相关性,特别是如果目录中的任何内容发生了更改。
对未合并的目录执行 Readdir 由底层目录(上层或下层)简单地处理。
重命名目录¶
当重命名位于下层或合并层上的目录时(即,该目录最初不是在上层创建的),overlayfs 可以通过两种不同的方式处理它
返回 EXDEV 错误:当尝试跨文件系统边界移动文件或目录时,rename(2) 会返回此错误。因此,应用程序通常会准备好处理此错误(例如,mv(1) 会递归复制目录树)。这是默认行为。
如果启用“redirect_dir”功能,则会向上复制目录(但不复制内容)。然后,“trusted.overlay.redirect”扩展属性会被设置为从overlay根目录到原始位置的路径。最后,该目录会被移动到新的位置。
有几种方法可以调整“redirect_dir”功能。
内核配置选项
- OVERLAY_FS_REDIRECT_DIR
如果启用此选项,则默认情况下启用redirect_dir。
- OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW
如果启用此选项,则默认情况下始终遵循重定向。启用此选项会导致安全性较低的配置。仅当担心与具有 redirect_dir 功能的内核向后兼容,并且即使关闭重定向也遵循重定向时,才启用此选项。
模块选项(也可以通过 /sys/module/overlay/parameters/ 更改)
- “redirect_dir=BOOL”
请参阅上面的OVERLAY_FS_REDIRECT_DIR内核配置选项。
- “redirect_always_follow=BOOL”
请参阅上面的OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW内核配置选项。
- “redirect_max=NUM”
绝对重定向中的最大字节数(默认为 256)。
挂载选项
- “redirect_dir=on”
启用重定向。
- “redirect_dir=follow”
不创建重定向,但遵循重定向。
- “redirect_dir=nofollow”
不创建也不遵循重定向。
- “redirect_dir=off”
如果在内核/模块配置中启用了“redirect_always_follow”,则此“off”会转换为“follow”,否则会转换为“nofollow”。
当启用NFS导出功能时,每个复制的目录都会按较低层inode的文件句柄进行索引,并且较高层目录的文件句柄会存储在索引条目的“trusted.overlay.upper”扩展属性中。在查找合并目录时,如果较高层目录与索引中存储的文件句柄不匹配,则表明多个较高层目录可能被重定向到同一个较低层目录。在这种情况下,查找会返回错误并警告可能存在不一致性。
由于无法使用索引验证较低层的重定向,因此在没有较高层的overlay文件系统上启用NFS导出支持需要关闭重定向跟踪(例如,“redirect_dir=nofollow”)。
非目录¶
非目录对象(文件、符号链接、设备特殊文件等)会根据需要从较高层或较低层文件系统中呈现。当以需要写访问的方式(例如,打开以进行写访问、更改某些元数据等)访问较低层文件系统中的文件时,首先将该文件从较低层文件系统复制到较高层文件系统(copy_up)。请注意,创建硬链接也需要 copy_up,但创建符号链接当然不需要。
copy_up 可能会变得不必要,例如,如果该文件以读写方式打开但数据未修改。
copy_up 过程首先确保包含目录存在于较高层文件系统中 - 根据需要创建该目录及其任何父目录。然后,它使用相同的元数据(所有者、模式、mtime、符号链接目标等)创建该对象,如果该对象是文件,则将数据从较低层复制到较高层文件系统。最后,复制任何扩展属性。
一旦 copy_up 完成,overlay 文件系统就会直接访问较高层文件系统中新创建的文件 - overlay 文件系统几乎不会注意到未来对该文件的操作(尽管会对文件名进行重命名或取消链接等操作会被注意到并处理)。
权限模型¶
overlay 文件系统中的权限检查遵循以下原则
权限检查应该在 copy_up 前后返回相同的结果
创建 overlay 挂载的任务不得获得额外的权限
与直接访问底层较低或较高层文件系统相比,非挂载任务可以通过 overlay 获得额外的权限
这是通过对每个访问执行两次权限检查来实现的
检查当前任务是否被允许基于本地 DAC(所有者、组、模式和 POSIX ACL)以及 MAC 检查进行访问
检查挂载任务是否被允许基于底层文件系统权限在较低或较高层上进行实际操作,同样包括 MAC 检查
检查 (a) 确保一致性 (1),因为所有者、组、模式和 POSIX ACL 会被复制。另一方面,它可能会导致忽略服务器强制执行的权限(例如,NFS 使用的权限)(3)。
检查 (b) 确保没有任务获得挂载任务不具有的底层权限 (2)。这也意味着可以创建不符合一致性规则 (1) 的设置;但通常,挂载任务将具有足够的权限来执行所有操作。
演示此模型的另一种方法是在
mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,... /merged
和
cp -a /lower /upper
mount --bind /upper /merged
之间进行类比。生成的访问权限应该相同。区别在于复制的时间(按需与预先)。
多个较低层¶
现在可以使用冒号 (“:”) 作为目录名称之间的分隔符来指定多个较低层。例如
mount -t overlay overlay -olowerdir=/lower1:/lower2:/lower3 /merged
如示例所示,“upperdir=” 和 “workdir=” 可以省略。在这种情况下,overlay 将是只读的。
指定的较低层目录将从最右边的目录开始,向左堆叠。在上面的示例中,lower1 将是顶层,lower2 是中间层,lower3 是底层。
注意:包含冒号的目录名称可以通过用单个反斜杠转义冒号来作为较低层提供。例如
mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged
从内核版本 v6.8 开始,还可以使用 “lowerdir+” 挂载选项和新挂载 API 中的 fsconfig 系统调用将包含冒号的目录名称配置为较低层。例如
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/a:lower::dir", 0);
在后一种情况下,较低层目录名称中的冒号在 /proc/self/mountinfo 中显示时将转义为八进制字符 (072)。
仅元数据复制¶
当启用“metacopy”功能时,当执行类似 chown/chmod 的特定于元数据的操作时,overlayfs 将仅复制元数据(而不是整个文件)。处于此状态的较高层文件会使用 “trusted.overlayfs.metacopy” xattr 标记,表示较高层文件不包含数据。当该文件打开以进行写入操作时,数据将在以后复制。在复制较低层文件的数据后,将从较高层文件中删除 “trusted.overlayfs.metacopy” xattr。
换句话说,这是一种延迟数据复制操作,当需要实际修改数据时才会复制数据。
有多种方法可以启用/禁用此功能。可以设置/取消设置配置选项 CONFIG_OVERLAY_FS_METACOPY 以默认启用/禁用此功能。或者,可以在模块加载时使用模块参数 metacopy=on/off 来启用/禁用它。最后,还有一个每个挂载的选项 metacopy=on/off 用于启用/禁用每个挂载的此功能。
请勿将 metacopy=on 与不受信任的较高层/较低层目录一起使用。否则,攻击者可能会创建一个包含适当 REDIRECT 和 METACOPY xattrs 的手工制作的文件,并获得对 REDIRECT 指向的较低层上的文件的访问权限。这在本地系统上不应该可行,因为设置 “trusted.” xattrs 将需要 CAP_SYS_ADMIN。但它对于来自 U 盘等不受信任的层应该是可行的。
注意:redirect_dir={off|nofollow|follow[*]} 和 nfs_export=on 挂载选项与 metacopy=on 冲突,并且会导致错误。
[*] 仅当指定 upperdir=... 时,redirect_dir=follow 才与 metacopy=on 冲突。
仅数据较低层¶
启用“metacopy”功能后,overlayfs 常规文件可能是来自最多三个不同层的信息的组合
来自较高层文件中元数据
来自较低层文件的 st_ino 和 st_dev 对象标识符
来自另一个较低层(更下方)的文件的的数据
“较低层数据”文件可以位于任何较低层上,但不能位于最顶层的较低层上。
在最顶层的较低层下方,可以使用双冒号 (“::”) 分隔符将任意数量的最底层定义为“仅数据”较低层。不允许普通较低层位于仅数据层下方,因此不允许在双冒号 (“::”) 分隔符的右侧使用单冒号分隔符。
例如
mount -t overlay overlay -olowerdir=/l1:/l2:/l3::/do1::/do2 /merged
“仅数据”较低层中的文件路径在合并的 overlayfs 目录中不可见,“仅数据”较低层中的文件的元数据和 st_ino/st_dev 在 overlayfs inode 中不可见。
仅当它上面一个较低层中的 “metacopy” 文件具有指向 “仅数据” 较低层中 “较低层数据” 文件的绝对路径的 “redirect” 时,“仅数据”较低层中的文件的数据才是可见的。
从内核版本 v6.8 开始,还可以使用 “datadir+” 挂载选项和新挂载 API 中的 fsconfig 系统调用添加 “仅数据” 较低层。例如
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l1", 0);
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l2", 0);
fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir+", "/l3", 0);
fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do1", 0);
fsconfig(fs_fd, FSCONFIG_SET_STRING, "datadir+", "/do2", 0);
通过文件描述符指定层¶
自内核 v6.13 起,overlayfs 除了可以将层指定为路径外,还支持通过文件描述符指定层。此功能可用于 “datadir+”、“lowerdir+”、“upperdir” 和 “workdir+” 挂载选项,以及来自新挂载 API 的 fsconfig 系统调用
fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower1);
fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower2);
fsconfig(fs_fd, FSCONFIG_SET_FD, "lowerdir+", NULL, fd_lower3);
fsconfig(fs_fd, FSCONFIG_SET_FD, "datadir+", NULL, fd_data1);
fsconfig(fs_fd, FSCONFIG_SET_FD, "datadir+", NULL, fd_data2);
fsconfig(fs_fd, FSCONFIG_SET_FD, "workdir", NULL, fd_work);
fsconfig(fs_fd, FSCONFIG_SET_FD, "upperdir", NULL, fd_upper);
fs-verity 支持¶
在较低层文件的元数据复制期间,如果源文件启用了 fs-verity 并且启用了 overlay verity 支持,则较低层文件的摘要会添加到 “trusted.overlay.metacopy” xattr。然后,此摘要用于在每次打开 metacopy 文件时验证较低层文件的内容。
当使用包含 verity xattr 的层时,这意味着保证较高层中的任何此类 metacopy 文件都与 copy-up 时较低层中的内容匹配。如果在任何时候(在挂载期间、重新挂载之后等)较低层中的此类文件被替换或以任何方式修改,则访问 overlayfs 中相应的的文件将导致 EIO 错误(在打开时,由于 overlayfs 摘要检查,或者由于 fs-verity 在后续读取时),并且详细的错误将打印到内核日志中。有关 fs-verity 文件访问的工作方式的更多详细信息,请参阅 Documentation/filesystems/fsverity.rst。
Verity 可用作检测正在使用的 overlayfs 目录中意外更改的常规可靠性检查。但是,如果格外小心,它还可以提供更强大的保证。例如,如果较高层是完全受信任的(通过使用 dm-verity 或类似方法),则可以使用不受信任的较低层来为所有 metacopy 文件提供经过验证的文件内容。如果此外,不受信任的较低层目录被指定为 “仅数据”,则它们只能提供此类文件内容,并且整个挂载可以被信任为与较高层匹配。
此功能由 “verity” 挂载选项控制,该选项支持以下值
- “off”
元复制摘要从不生成或使用。如果未指定 verity 选项,则这是默认设置。
- “on”
每当元复制文件指定了预期摘要时,相应的数据文件必须与指定的摘要匹配。在生成元复制文件时,将根据源文件(如果有)在其内部设置 verity 摘要。
- “require”
与 “on” 相同,但此外,所有元复制文件都必须指定一个摘要(否则在打开时会返回 EIO)。这意味着只有在数据文件启用了 fs-verity 时才会使用元数据复制,否则将使用完整复制。
嵌套 overlayfs 挂载¶
可以使用存储在 overlayfs 挂载上的较低目录。对于常规文件,这不需要任何特别的注意。但是,具有 overlayfs 属性的文件,例如白化文件或 “overlay.*” xattrs,将被底层 overlayfs 挂载解释并删除。为了允许第二个 overlayfs 挂载看到这些属性,它们必须被转义。
overlayfs 特定的 xattrs 使用特殊的 “overlay.overlay.” 前缀进行转义。因此,下层目录中具有 “trusted.overlay.overlay.metacopy” xattr 的文件将在 overlayfs 挂载中作为具有 “trusted.overlay.metacopy” xattr 的常规文件公开。这可以通过多次重复前缀进行嵌套,因为每个实例仅删除一个前缀。
一个带有常规白化文件的下层目录将始终由 overlayfs 挂载处理,因此为了支持在 overlayfs 挂载中存储有效的白化文件,支持一种替代形式的白化文件。这种形式是一个常规的零大小文件,其中 “overlay.whiteout” xattr 设置在 “overlay.opaque” xattr 设置为 “x” 的目录中(请参阅白化文件和不透明目录)。这些替代白化文件永远不会由 overlayfs 创建,但可以由生成下层文件的用户空间工具(如容器)使用。这些替代白化文件可以使用标准的 xattr 转义机制进行转义,以便正确地嵌套到任何深度。
非标准行为¶
当前版本的 overlayfs 可以充当一个基本符合 POSIX 的文件系统。
以下是 overlayfs 当前未处理的情况列表
POSIX 规定更新读取的 st_atime。当文件位于较低层时,当前不会执行此操作。
如果位于较低层的文件以只读方式打开,然后使用 MAP_SHARED 进行内存映射,则随后对文件的更改不会反映在内存映射中。
如果正在执行位于较低层的文件,则打开该文件进行写入或截断该文件将不会被 ETXTBSY 拒绝。
以下选项允许 overlayfs 更像一个符合标准的文件系统
redirect_dir¶
使用挂载选项或模块选项启用:“redirect_dir=on” 或使用内核配置选项 CONFIG_OVERLAY_FS_REDIRECT_DIR=y。
如果禁用此功能,则对较低或合并目录执行 rename(2) 将因 EXDEV (“无效的跨设备链接”) 而失败。
index¶
使用挂载选项或模块选项 “index=on” 或使用内核配置选项 CONFIG_OVERLAY_FS_INDEX=y 启用。
如果禁用此功能并且复制了具有多个硬链接的文件,则这将“破坏”链接。更改不会传播到引用同一 inode 的其他名称。
xino¶
使用挂载选项 “xino=auto” 或 “xino=on”,使用模块选项 “xino_auto=on” 或使用内核配置选项 CONFIG_OVERLAY_FS_XINO_AUTO=y 启用。通过对构成 overlay 的所有层使用相同的底层文件系统也会隐式启用。
如果禁用此功能或者底层文件系统的 inode 号中没有足够的空闲位,则 overlayfs 将无法保证 stat(2) 返回的 st_ino 和 st_dev 值以及 readdir(3) 返回的 d_ino 值的行为与正常文件系统类似。例如,同一 overlay 文件系统中的两个对象的 st_dev 值可能不同,并且文件系统对象的 st_ino 值可能不是持久的,甚至在 overlay 文件系统挂载时也可能会更改,如上面的Inode 属性表中总结的那样。
底层文件系统的更改¶
不允许更改作为已挂载 overlay 文件系统一部分的底层文件系统。如果底层文件系统被更改,则 overlay 的行为是未定义的,尽管不会导致崩溃或死锁。
当 overlay 未挂载时,允许对上层树进行离线更改。只有在未使用 “metacopy”、“index”、“xino” 和 “redirect_dir” 功能的情况下,才允许对下层树进行离线更改。如果修改了下层树并且使用了这些功能中的任何一个,则 overlay 的行为是未定义的,尽管不会导致崩溃或死锁。
当启用 overlay NFS 导出功能时,overlay 文件系统在底层下层离线更改时的行为与禁用 NFS 导出时的行为不同。
在每次 copy_up 时,下层 inode 的 NFS 文件句柄以及下层文件系统的 UUID 都将被编码并存储在上层 inode 的扩展属性 “trusted.overlay.origin” 中。
当启用 NFS 导出功能时,在查找路径或由 “trusted.overlay.redirect” 扩展属性指向的路径处找到下层目录的合并目录时,将验证找到的下层目录文件句柄和下层文件系统 UUID 是否与在 copy_up 时存储的源文件句柄匹配。如果找到的下层目录与存储的源不匹配,则该目录将不会与上层目录合并。
NFS 导出¶
当底层文件系统支持 NFS 导出并且启用了 “nfs_export” 功能时,可以将 overlay 文件系统导出到 NFS。
使用 “nfs_export” 功能,在复制任何下层对象时,将在索引目录下的创建一个索引条目。索引条目名称是复制源文件句柄的十六进制表示形式。对于非目录对象,索引条目是上层 inode 的硬链接。对于目录对象,索引条目具有扩展属性 “trusted.overlay.upper”,其中包含上层目录 inode 的编码文件句柄。
在编码 overlay 文件系统对象的文件句柄时,适用以下规则
对于非上层对象,从下层 inode 编码下层文件句柄
对于索引对象,从 copy_up 源编码下层文件句柄
对于纯上层对象和现有的非索引上层对象,从上层 inode 编码上层文件句柄
编码的 overlay 文件句柄包括
包括路径类型信息(例如,下层/上层)的标头
底层文件系统的 UUID
底层 inode 的底层文件系统编码
此编码格式与存储在扩展属性 “trusted.overlay.origin” 中的文件句柄的编码格式相同。
解码 overlay 文件句柄时,遵循以下步骤
通过 UUID 和路径类型信息查找底层层。
将底层文件系统文件句柄解码为底层 dentry。
对于下层文件句柄,按名称在索引目录中查找句柄。
如果在索引中找到白化文件,则返回 ESTALE。这表示在编码其文件句柄后被删除的 overlay 对象。
对于非目录,从解码的底层 dentry、路径类型和索引 inode(如果找到)实例化一个断开连接的 overlay dentry。
对于目录,使用连接的底层解码的 dentry、路径类型和索引来查找连接的 overlay dentry。
解码非目录文件句柄可能会返回断开连接的 dentry。该断开连接的 dentry 的 copy_up 将创建一个没有上层别名的上层索引条目。
当 overlay 文件系统具有多个下层时,中间层目录可能具有到下层目录的“重定向”。由于中间层“重定向”没有索引,因此无法使用从“重定向”源目录编码的下层文件句柄来查找中间层或上层目录。同样,无法使用从“重定向”源目录的后代编码的下层文件句柄来重建连接的 overlay 路径。为了缓解无法从下层文件句柄解码目录的情况,这些目录会在编码时被复制并编码为上层文件句柄。在没有上层的 overlay 文件系统上,此缓解措施无法使用,此设置中的 NFS 导出需要关闭重定向跟随(例如,“redirect_dir=nofollow”)。
overlay 文件系统不支持非目录可连接文件句柄,因此使用“subtree_check”exportfs 配置导出将导致无法通过 NFS 查找文件。
当启用 NFS 导出功能时,所有目录索引条目都会在挂载时进行验证,以检查上层文件句柄是否不是过时的。在某些情况下,此验证可能会导致明显的开销。
注意:挂载选项 index=off,nfs_export=on 对于读写挂载是冲突的,将导致错误。
注意:挂载选项 uuid=off 可以用来将文件句柄中底层文件系统的 UUID 替换为 null,从而有效地禁用 UUID 检查。这在底层磁盘被复制并且该副本的 UUID 发生变化的情况下很有用。这仅适用于所有 lower/upper/work 目录位于同一文件系统的情况,否则将回退到正常行为。
UUID 和 fsid¶
overlayfs 实例本身的 UUID 和 statfs(2) 报告的 fsid 由 “uuid” 挂载选项控制,该选项支持以下值:
- “null”
overlayfs 的 UUID 为 null。fsid 取自最上层的文件系统。
- “off”
overlayfs 的 UUID 为 null。fsid 取自最上层的文件系统。底层层的 UUID 将被忽略。
- “on”
overlayfs 的 UUID 将被生成并用于报告唯一的 fsid。UUID 存储在 xattr “trusted.overlay.uuid” 中,使 overlayfs 的 fsid 唯一且持久。此选项需要一个带有支持 xattr 的 upper 文件系统的 overlayfs。
- “auto”:(默认)
如果存在,UUID 取自 xattr “trusted.overlay.uuid”。在首次挂载符合先决条件的新 overlay 文件系统时升级为 “uuid=on”。对于从未以 “uuid=on” 挂载过的现有 overlay 文件系统,降级为 “uuid=null”。
易失性挂载¶
使用 “volatile” 挂载选项启用。不能保证易失性挂载在崩溃后仍然存在。强烈建议仅在写入 overlay 的数据可以毫不费力地重新创建的情况下才使用易失性挂载。
使用 “volatile” 选项挂载的优点是省略了对 upper 文件系统的所有形式的同步调用。
为了避免产生虚假的安全感,易失性挂载的 syncfs(和 fsync)语义与 VFS 的其余部分略有不同。如果在发生易失性挂载后 upperdir 的文件系统上发生任何回写错误,所有同步函数都将返回错误。一旦达到此条件,文件系统将不会恢复,并且每次后续的同步调用都将返回错误,即使自上次同步调用以来 upperdir 没有发生新的错误。
当使用 “volatile” 选项挂载 overlay 时,将创建目录 “$workdir/work/incompat/volatile”。在下次挂载期间,overlay 会检查此目录,如果存在则拒绝挂载。这强烈表明用户应该丢弃 upper 和 work 目录并创建新的目录。在用户知道系统没有崩溃并且 upperdir 的内容完好无损的非常有限的情况下,可以删除 “volatile” 目录。
用户 xattr¶
“-o userxattr” 挂载选项强制 overlayfs 使用 “user.overlay.” xattr 命名空间而不是 “trusted.overlay.”。这对于以非特权方式挂载 overlayfs 很有用。
测试套件¶
有一个最初由 David Howells 开发并目前由 Amir Goldstein 维护的测试套件,网址为:
https://github.com/amir73il/unionmount-testsuite.git
以 root 身份运行
# cd unionmount-testsuite
# ./run --ov --verify