登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  linux

Linux mount --bind 与 --rbind 的子挂载差异

来源:17golang原创

时间:2026-11-01 10:24:15 138浏览 收藏

把目录映射到另一个位置时,mount --bind 和 mount --rbind 的关键差别不是“是否递归复制普通文件”,而是“是否把源目录下已经存在的子挂载一并挂过去”。普通 bind 只附着指定的挂载点;rbind 会递归处理这棵挂载树。

这篇用一个带子挂载的目录模型说明两条命令的边界,并给出检查和清理方式。示例只用于解释结构,实际执行前应确认源目录、目标目录和当前挂载命名空间都属于你的维护范围。

官方资料:https://docs.kernel.org/filesystems/sharedsubtree.html

先分清目录树与挂载树

假设源路径是 /srv/project,它下面有普通目录 config,还有一个独立挂载在 data 上。目录树看起来只有一个父目录和两个子目录,但挂载树实际上多了一层“挂载在 data 上的文件系统”。

--bind 复制的是指定的挂载点关系:它让目标路径看到 /srv/project 这个整体,但不会自动把 /srv/project/data 的独立子挂载再复制一份。--rbind 的 r 表示 recursive,会沿着源挂载树处理子挂载,所以目标下的 data 仍然对应一个子挂载。

Linux mount bind 与 rbind 的源目录、子挂载和两个目标挂载关系说明图
图1:结构说明图,对比 --bind 只附着源挂载点与 --rbind 保留子挂载树的差异。

用最小项目模型对比两条命令

为了把差异固定下来,可以把源目录和两个目标目录看成一个小型挂载实验的资源边界。下面的命令是可复制的示例,中文注释说明每组命令的目的;它不会在本文写作过程中被执行。

# 准备源目录和两个目标目录,避免目标路径已经是挂载点
sudo mkdir -p /srv/project/config /srv/project/data
sudo mkdir -p /mnt/project-bind /mnt/project-rbind

# 普通 bind:只建立源挂载点到目标挂载点的映射
sudo mount --bind /srv/project /mnt/project-bind

# 递归 bind:把源目录下面已有的子挂载也纳入目标树
sudo mount --rbind /srv/project /mnt/project-rbind

# 用树状视图查看两个目标各自包含哪些挂载
findmnt -R /mnt/project-bind
findmnt -R /mnt/project-rbind

如果 data 只是一个普通目录,两条命令看起来可能接近;只有当 data 本身是独立挂载点时,--rbind 才会体现出递归差异。这也是排查“映射过去后子目录内容不对”的第一处判断。

不要把 cp -a 或目录遍历和 rbind 混为一谈。rbind 不复制文件内容,它建立的是挂载关系;源文件系统的变化和挂载属性仍受当前挂载命名空间与传播规则影响。

用 findmnt 看清子挂载和传播属性

只执行 ls 很难判断某个目录是普通目录还是独立挂载。findmnt -R 更适合看目标路径下的挂载树,重点观察目标本身、data 子路径以及它们的文件系统类型和挂载选项。

# 只查看目标树,避免把整台机器的挂载混在一起
findmnt -R /mnt/project-bind
findmnt -R /mnt/project-rbind

# 查看挂载传播状态,排查 shared、slave 或 private 边界
findmnt -o TARGET,SOURCE,FSTYPE,OPTIONS,PROPAGATION \
  /mnt/project-bind /mnt/project-rbind

检查时可以按三点读结果:第一,目标根是否出现;第二,源目录中的独立子挂载是否在 rbind 目标下出现;第三,PROPAGATION 是否显示了 shared、slave 或 private。第三点属于传播语义,不由“r”这个字母单独决定。

Linux rbind 目标挂载树、findmnt 检查和传播属性边界说明图
图2:边界说明图,展示递归目标、子挂载检查和 shared/private 传播属性之间的静态关系。

什么时候选 bind,什么时候选 rbind

只需要把一个目录作为单一入口暴露给另一个路径时,优先考虑 --bind。例如把一个配置目录或单个数据目录映射到服务工作目录,排除不希望跟随的子挂载更容易控制。

需要保留完整挂载树时再用 --rbind,常见于把一棵系统目录树放进另一个根目录、准备隔离环境或映射包含多个独立文件系统的目录。使用前要确认源树中没有不应暴露的挂载点,因为递归范围比普通 bind 大。

如果环境还涉及跨命名空间的挂载传播,不要仅靠 --rbind 推断行为。内核文档把 bind/rbind 与 shared、slave、private、unbindable 状态分开描述;需要隔离时,应明确检查并设置传播属性,而不是把递归复制当成传播控制。

清理时别漏掉递归目标

普通 bind 目标通常可以直接卸载;rbind 目标可能包含多个子挂载,清理时应先确认目标树,再递归卸载目标。示例中的 umount -R 是清理目标树的表达方式,实际环境还要结合发行版的 util-linux 版本和是否存在繁忙进程。

# 先确认递归目标下有哪些挂载,避免误卸载相邻资源
findmnt -R /mnt/project-rbind

# 递归卸载 rbind 目标及其子挂载
sudo umount -R /mnt/project-rbind

# 普通 bind 目标没有需要保留的子挂载时再单独卸载
sudo umount /mnt/project-bind

若卸载失败,先看目标是否被进程占用、是否有子挂载仍在树中,以及目标是否处于共享传播关系。不要直接扩大卸载范围;把 findmnt -R 的结果和目标路径对应起来,通常比反复重试更安全。

常见问题

为什么 bind 后看不到源目录里的挂载内容? 如果子路径是独立挂载点,这是普通 bind 的预期边界;需要连同挂载树一起映射时改用 --rbind,并检查目标的递归结果。

rbind 是否会复制文件? 不会。它复制的是挂载关系,不是目录内容;文件仍由对应的文件系统和挂载命名空间提供。

--rbind 能否代替传播属性设置? 不能。递归挂载和 shared/private 等传播状态是两个维度,必须分别检查和配置。

可以把选择记成一句话:只映射一个挂载点用 --bind,需要保留其下独立子挂载时用 --rbind;无论选择哪一种,都先用 findmnt -R 确认范围,再按目标树清理。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>